diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d9c43c1..4d49560 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,6 @@ jobs: - name: Run Tests run: > dotnet test - --filter FullyQualifiedName!~Integration -p:CollectCoverage=true -p:CoverletOutput=TestResults/ -p:CoverletOutputFormat=opencover @@ -40,6 +39,10 @@ jobs: -m:1 --configuration Release --no-build + env: + Nordigen__BaseAddress: https://ob.nordigen.com/ + Nordigen__SecretId: ${{ secrets.NORDIGEN_SECRET_ID }} + Nordigen__SecretKey: ${{ secrets.NORDIGEN_SECRET_KEY }} - name: ReSharper annotations uses: VMelnalksnis/resharper-inspect-action@v0.2.2 diff --git a/source/VMelnalksnis.NordigenDotNet/Requisitions/Requisition.cs b/source/VMelnalksnis.NordigenDotNet/Requisitions/Requisition.cs index f9ecffa..5c27471 100644 --- a/source/VMelnalksnis.NordigenDotNet/Requisitions/Requisition.cs +++ b/source/VMelnalksnis.NordigenDotNet/Requisitions/Requisition.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; using NodaTime; @@ -19,7 +18,6 @@ namespace VMelnalksnis.NordigenDotNet.Requisitions; /// The URI to which the user will be redirected after authorizing access. /// The status of the requisition. /// The ID of the institution for which this requisition was made for. -/// The end-user-agreement of this requisition. /// Client specified reference for this requisition. /// Accounts retrieved within the scope of this requisition. /// URI to initiate the authorization with the institution. @@ -31,13 +29,20 @@ public record Requisition( Uri Redirect, RequisitionStatus Status, [property: JsonPropertyName("institution_id")] string InstitutionId, - string Agreement, string Reference, List Accounts, Uri Link, [property: JsonPropertyName("account_selection")] bool AccountSelection, [property: JsonPropertyName("redirect_immediate")] bool RedirectImmediate) { + /// The raw value of . + [JsonPropertyName("agreement")] + public string? AgreementValue { get; init; } + + /// The end-user-agreement of this requisition. + [JsonIgnore] + public Guid? Agreement => string.IsNullOrWhiteSpace(AgreementValue) ? null : Guid.Parse(AgreementValue); + /// A two-letter country code (ISO 639-1). [JsonPropertyName("user_language")] public string? UserLanguage { get; init; } diff --git a/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Accounts/AccountClientTests.cs b/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Accounts/AccountClientTests.cs index 78239b5..e4f91e4 100644 --- a/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Accounts/AccountClientTests.cs +++ b/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Accounts/AccountClientTests.cs @@ -5,33 +5,28 @@ using System.Linq; using System.Threading.Tasks; -using VMelnalksnis.NordigenDotNet.Accounts; -using VMelnalksnis.NordigenDotNet.Requisitions; - namespace VMelnalksnis.NordigenDotNet.Tests.Integration.Accounts; public sealed class AccountClientTests : IClassFixture { - private readonly IAccountClient _accountClient; - private readonly IRequisitionClient _requisitionClient; + private readonly INordigenClient _nordigenClient; public AccountClientTests(ServiceProviderFixture serviceProviderFixture) { - _accountClient = serviceProviderFixture.AccountClient; - _requisitionClient = serviceProviderFixture.RequisitionClient; + _nordigenClient = serviceProviderFixture.NordigenClient; } - [Fact] + [Fact(Skip = "Requires manual setup at least every 90 days")] public async Task Get() { - var requisition = await _requisitionClient.Get().SingleAsync(); + var requisition = await _nordigenClient.Requisitions.Get().SingleAsync(); foreach (var id in requisition.Accounts) { - await _accountClient.Get(id); - await _accountClient.GetDetails(id); - await _accountClient.GetBalances(id); - await _accountClient.GetTransactions(id); + await _nordigenClient.Accounts.Get(id); + await _nordigenClient.Accounts.GetDetails(id); + await _nordigenClient.Accounts.GetBalances(id); + await _nordigenClient.Accounts.GetTransactions(id); } } } diff --git a/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Agreements/AgreementClientTests.cs b/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Agreements/AgreementClientTests.cs index 7e36a35..8dc1b58 100644 --- a/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Agreements/AgreementClientTests.cs +++ b/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Agreements/AgreementClientTests.cs @@ -7,17 +7,19 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; +using NodaTime; + using VMelnalksnis.NordigenDotNet.Agreements; namespace VMelnalksnis.NordigenDotNet.Tests.Integration.Agreements; public sealed class AgreementClientTests : IClassFixture { - private readonly IAgreementClient _agreementClient; + private readonly INordigenClient _nordigenClient; public AgreementClientTests(ServiceProviderFixture serviceProviderFixture) { - _agreementClient = serviceProviderFixture.AgreementClient; + _nordigenClient = serviceProviderFixture.NordigenClient; } [Fact] @@ -25,8 +27,20 @@ public sealed class AgreementClientTests : IClassFixture { var creation = new EndUserAgreementCreation("CITADELE_PARXLV22"); - var createdAgreement = await _agreementClient.Post(creation); - var agreements = await _agreementClient.Get().ToListAsync(); + var createdAgreement = await _nordigenClient.Agreements.Post(creation); + (await _nordigenClient.Agreements.Get(createdAgreement.Id)).Should().BeEquivalentTo(createdAgreement); + + using (new AssertionScope()) + { + createdAgreement.Created.Should().BeGreaterThan(SystemClock.Instance.GetCurrentInstant() - Duration.FromSeconds(5)); + createdAgreement.Accepted.Should().BeNull(); + createdAgreement.MaxHistoricalDays.Should().Be(90); + createdAgreement.AccessValidForDays.Should().Be(90); + createdAgreement.AccessScope.Should().BeEquivalentTo("balances", "details", "transactions"); + createdAgreement.InstitutionId.Should().Be(creation.InstitutionId); + } + + var agreements = await _nordigenClient.Agreements.Get().ToListAsync(); agreements .Should() @@ -36,16 +50,16 @@ public sealed class AgreementClientTests : IClassFixture var acceptance = new EndUserAgreementAcceptance("NordigenDotNet integration test", "127.0.0.1"); (await FluentActions - .Awaiting(() => _agreementClient.Put(createdAgreement.Id, acceptance)) + .Awaiting(() => _nordigenClient.Agreements.Put(createdAgreement.Id, acceptance)) .Should() .ThrowExactlyAsync()) .Which.StatusCode.Should() .Be(HttpStatusCode.Forbidden, "test company cannot create agreements"); - await _agreementClient.Delete(createdAgreement.Id); + await _nordigenClient.Agreements.Delete(createdAgreement.Id); (await FluentActions - .Awaiting(() => _agreementClient.Get(createdAgreement.Id)) + .Awaiting(() => _nordigenClient.Agreements.Get(createdAgreement.Id)) .Should() .ThrowExactlyAsync()) .Which.StatusCode.Should() diff --git a/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Institutions/InstitutionClientTests.cs b/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Institutions/InstitutionClientTests.cs index 05ca476..3867cda 100644 --- a/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Institutions/InstitutionClientTests.cs +++ b/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Institutions/InstitutionClientTests.cs @@ -2,30 +2,39 @@ // Licensed under the Apache License 2.0. // See LICENSE file in the project root for full license information. +using System; using System.Threading.Tasks; -using VMelnalksnis.NordigenDotNet.Institutions; - namespace VMelnalksnis.NordigenDotNet.Tests.Integration.Institutions; public sealed class InstitutionClientTests : IClassFixture { - private readonly IInstitutionClient _institutionClient; + private readonly INordigenClient _nordigenClient; public InstitutionClientTests(ServiceProviderFixture serviceProviderFixture) { - _institutionClient = serviceProviderFixture.InstitutionClient; + _nordigenClient = serviceProviderFixture.NordigenClient; } [Fact] public async Task GetByCountry() { - var institutions = await _institutionClient.GetByCountry("LV"); + var institutions = await _nordigenClient.Institutions.GetByCountry("LV"); institutions.Count.Should().Be(17); var expectedInstitution = institutions.Should().ContainSingle(i => i.Id == "CITADELE_PARXLV22").Subject; - var institution = await _institutionClient.Get(expectedInstitution.Id); + var institution = await _nordigenClient.Institutions.Get(expectedInstitution.Id); institution.Should().BeEquivalentTo(expectedInstitution); + + using (new AssertionScope()) + { + institution.Id.Should().Be("CITADELE_PARXLV22"); + institution.Name.Should().Be("Citadele"); + institution.Bic.Should().Be("PARXLV22"); + institution.TransactionTotalDays.Should().Be(730); + institution.Countries.Should().ContainSingle().Which.Should().Be("LV"); + institution.Logo.Should().Be(new Uri("https://cdn.nordigen.com/ais/CITADELE_PARXLV22.png")); + } } } diff --git a/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Requisitions/RequisitionsClientTests.cs b/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Requisitions/RequisitionsClientTests.cs index 8539c56..7235cd0 100644 --- a/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Requisitions/RequisitionsClientTests.cs +++ b/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/Requisitions/RequisitionsClientTests.cs @@ -7,40 +7,64 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; +using NodaTime; + using VMelnalksnis.NordigenDotNet.Requisitions; namespace VMelnalksnis.NordigenDotNet.Tests.Integration.Requisitions; public sealed class RequisitionsClientTests : IClassFixture { - private readonly IRequisitionClient _requisitionClient; + private readonly INordigenClient _nordigenClient; public RequisitionsClientTests(ServiceProviderFixture serviceProviderFixture) { - _requisitionClient = serviceProviderFixture.RequisitionClient; + _nordigenClient = serviceProviderFixture.NordigenClient; } [Fact] public async Task Get() { - var requisitions = await _requisitionClient.Get().ToListAsync(); + var requisitions = await _nordigenClient.Requisitions.Get().ToListAsync(); var expectedRequisition = requisitions.Should().ContainSingle().Subject; - var requisition = await _requisitionClient.Get(expectedRequisition.Id); + var requisition = await _nordigenClient.Requisitions.Get(expectedRequisition.Id); requisition.Should().BeEquivalentTo(expectedRequisition); } [Fact] - public async Task Post() + public async Task CreateAndDelete() { - var creation = new RequisitionCreation(new("https://gnomeshade.org/"), "CITADELE_PARXLV22"); + var creation = new RequisitionCreation(new("https://github.com/VMelnalksnis/NordigenDotNet"), "CITADELE_PARXLV22"); + var requisition = await _nordigenClient.Requisitions.Post(creation); + var requisitions = await _nordigenClient.Requisitions.Get().ToListAsync(); - var requisition = await _requisitionClient.Post(creation); + using (new AssertionScope()) + { + requisition.Created.Should().BeGreaterThan(SystemClock.Instance.GetCurrentInstant() - Duration.FromSeconds(5)); + requisition.Redirect.Should().Be(creation.Redirect); + requisition.Status.Should().Be(RequisitionStatus.Cr); + requisition.InstitutionId.Should().BeEquivalentTo(creation.InstitutionId); + requisition.Reference.Should().NotBeNullOrWhiteSpace("Nordigen sets it to a random GUID if not specified"); + requisition.Accounts.Should().BeEmpty("accounts are not returned before user authorizes it"); + requisition.Link.AbsoluteUri.Should().Contain("nordigen"); + requisition.AccountSelection.Should().BeFalse(); + requisition.RedirectImmediate.Should().BeFalse(); + requisition.Agreement.Should().BeNull(); + requisition.UserLanguage.Should().BeNull(); + requisition.Ssn.Should().BeNull(); + } - await _requisitionClient.Delete(requisition.Id); + requisitions + .Should() + .ContainSingle(r => r.Id == requisition.Id) + .Which.Should() + .BeEquivalentTo(requisition); + + await _nordigenClient.Requisitions.Delete(requisition.Id); (await FluentActions - .Awaiting(() => _requisitionClient.Get(requisition.Id)) + .Awaiting(() => _nordigenClient.Requisitions.Get(requisition.Id)) .Should() .ThrowExactlyAsync()) .Which.StatusCode diff --git a/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/ServiceProviderFixture.cs b/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/ServiceProviderFixture.cs index 9df369b..533b5eb 100644 --- a/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/ServiceProviderFixture.cs +++ b/tests/VMelnalksnis.NordigenDotNet.Tests.Integration/ServiceProviderFixture.cs @@ -11,11 +11,7 @@ using Microsoft.Extensions.DependencyInjection; using NodaTime; -using VMelnalksnis.NordigenDotNet.Accounts; -using VMelnalksnis.NordigenDotNet.Agreements; using VMelnalksnis.NordigenDotNet.DependencyInjection; -using VMelnalksnis.NordigenDotNet.Institutions; -using VMelnalksnis.NordigenDotNet.Requisitions; namespace VMelnalksnis.NordigenDotNet.Tests.Integration; @@ -37,11 +33,5 @@ public sealed class ServiceProviderFixture _serviceProvider = serviceCollection.BuildServiceProvider(); } - public IAccountClient AccountClient => _serviceProvider.GetRequiredService(); - - public IAgreementClient AgreementClient => _serviceProvider.GetRequiredService(); - - public IInstitutionClient InstitutionClient => _serviceProvider.GetRequiredService(); - - public IRequisitionClient RequisitionClient => _serviceProvider.GetRequiredService(); + public INordigenClient NordigenClient => _serviceProvider.GetRequiredService(); }