Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using System.Text.Json;
using Adyen.BalancePlatform.Client;
using Adyen.BalancePlatform.Extensions;
using Adyen.Core.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Adyen.BalancePlatform.Models;
using Adyen.BalancePlatform.Services;
using System.Net;
using Adyen.Core.Client;
using NSubstitute;

namespace Adyen.Test.BalancePlatform.SCAAssociationManagement
{
[TestClass]
public class SCAAssociationManagementServiceTest
{
private readonly JsonSerializerOptionsProvider _jsonSerializerOptionsProvider;
private readonly ISCAAssociationManagementService _scaAssociationManagementService;

public SCAAssociationManagementServiceTest()
{
var host = Host.CreateDefaultBuilder()
.ConfigureBalancePlatform((context, services, config) =>
{
config.ConfigureAdyenOptions(options =>
{
options.AdyenApiKey = context.Configuration["ADYEN_API_KEY"];
options.Environment = AdyenEnvironment.Test;
});
})
.Build();

_jsonSerializerOptionsProvider = host.Services.GetRequiredService<JsonSerializerOptionsProvider>();
_scaAssociationManagementService = Substitute.For<ISCAAssociationManagementService>();
}

[TestMethod]
public async Task Given_ApproveAssociationRequestWithWWWAuthenticate_SendsCorrectRequest()
{
// Arrange
string requestJson =
TestUtilities.GetTestFileContent("mocks/balanceplatform/ApproveAssociationRequest.json");
var approveAssociationRequest =
JsonSerializer.Deserialize<ApproveAssociationRequest>(requestJson,
_jsonSerializerOptionsProvider.Options);

var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.Unauthorized);
httpResponseMessage.Headers.Add("sdkInput", "dummy_sdk_input_string");
var mockApiResponse = new SCAAssociationManagementService.ApproveAssociationApiResponse(
Substitute.For<Microsoft.Extensions.Logging.ILogger<SCAAssociationManagementService.ApproveAssociationApiResponse>>(),
new HttpRequestMessage(),
httpResponseMessage,
"{}", // A 401 would typically return an error object, but for this test, we are just focusing on the header.
"/scaAssociations",
DateTime.UtcNow,
_jsonSerializerOptionsProvider.Options
);

var requestOptions = new RequestOptions();
requestOptions.AddWWWAuthenticateHeader("TestAuthValue");

_scaAssociationManagementService.ApproveAssociationAsync(
Arg.Is<ApproveAssociationRequest>(req =>
req.EntityId == approveAssociationRequest.EntityId &&
req.EntityType == approveAssociationRequest.EntityType &&
req.ScaDeviceIds.SequenceEqual(approveAssociationRequest.ScaDeviceIds)
),
Arg.Is<RequestOptions>(opt =>
opt.Headers.ContainsKey("WWW-Authenticate") &&
opt.Headers["WWW-Authenticate"] == "TestAuthValue"
),
Arg.Any<CancellationToken>()
)
.Returns(Task.FromResult<IApproveAssociationApiResponse>(mockApiResponse));

// Act
var response = await _scaAssociationManagementService.ApproveAssociationAsync(approveAssociationRequest, requestOptions);

// Assert
Assert.IsNotNull(response);
Assert.IsTrue(response.IsUnauthorized);
Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode); // 401
Assert.IsTrue(response.Headers.Contains("sdkInput"));
Assert.AreEqual("dummy_sdk_input_string", response.Headers.GetValues("sdkInput").Single());
Assert.IsNotNull(response.Unauthorized()); // Assert that the Unauthorized method returns a deserialized error object

// Verify that the mocked method was called with the correct arguments
await _scaAssociationManagementService.Received(1).ApproveAssociationAsync(
Arg.Is<ApproveAssociationRequest>(req =>
req.EntityId == approveAssociationRequest.EntityId &&
req.EntityType == approveAssociationRequest.EntityType &&
req.ScaDeviceIds.SequenceEqual(approveAssociationRequest.ScaDeviceIds)
),
Arg.Is<RequestOptions>(opt =>
opt.Headers.ContainsKey("WWW-Authenticate") &&
opt.Headers["WWW-Authenticate"] == "TestAuthValue"
),
Arg.Any<CancellationToken>()
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using System.Text.Json;
using Adyen.BalancePlatform.Client;
using Adyen.BalancePlatform.Extensions;
using Adyen.BalancePlatform.Models;
using Adyen.Core.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Adyen.Test.BalancePlatform.SCAAssociationManagement
{
[TestClass]
public class SCAAssociationManagementTest : BaseTest
{
private readonly JsonSerializerOptionsProvider _jsonSerializerOptionsProvider;

public SCAAssociationManagementTest()
{
IHost host = Host.CreateDefaultBuilder()
.ConfigureBalancePlatform((context, services, config) =>
{
config.ConfigureAdyenOptions(options =>
{
options.AdyenApiKey = context.Configuration["ADYEN_API_KEY"];
options.Environment = AdyenEnvironment.Test;
});
})
.Build();

_jsonSerializerOptionsProvider = host.Services.GetRequiredService<JsonSerializerOptionsProvider>();
}

[TestMethod]
public async Task Given_ApproveAssociationRequest_Deserialize_Correctly()
{
// Arrange
string json = TestUtilities.GetTestFileContent("mocks/balanceplatform/ApproveAssociationRequest.json");

// Act
var response = JsonSerializer.Deserialize<ApproveAssociationRequest>(json, _jsonSerializerOptionsProvider.Options);

// Assert
Assert.IsNotNull(response);
Assert.AreEqual(response.Status, AssociationStatus.Active);
Assert.AreEqual(response.EntityType, ScaEntityType.AccountHolder);
Assert.AreEqual(response.EntityId, "AH00000000000000000000001");
Assert.AreEqual(response.ScaDeviceIds.Count, 1);
Assert.AreEqual(response.ScaDeviceIds[0], "BSDR42XV3223223S5N6CDQDGH53M8H");
}

[TestMethod]
public async Task Given_ApproveAssociationResponse_Deserialize_Correctly()
{
// Arrange
string json = TestUtilities.GetTestFileContent("mocks/balanceplatform/ApproveAssociationResponse.json");

// Act
var response = JsonSerializer.Deserialize<ApproveAssociationResponse>(json, _jsonSerializerOptionsProvider.Options);

// Assert
Assert.IsNotNull(response);
Assert.AreEqual(response.ScaAssociations.Count, 1);
var association = response.ScaAssociations[0];
Assert.AreEqual(association.Status, AssociationStatus.Active);
Assert.AreEqual(association.EntityType, ScaEntityType.AccountHolder);
Assert.AreEqual(association.EntityId, "AH00000000000000000000001");
Assert.AreEqual(association.ScaDeviceId, "BSDR42XV3223223S5N6CDQDGH53M8H");
}

[TestMethod]
public async Task Given_ListAssociationsResponse_Deserialize_Correctly()
{
// Arrange
string json = TestUtilities.GetTestFileContent("mocks/balanceplatform/ListAssociationsResponse.json");

// Act
var response = JsonSerializer.Deserialize<ListAssociationsResponse>(json, _jsonSerializerOptionsProvider.Options);

// Assert
Assert.IsNotNull(response);
Assert.IsNotNull(response.Links);
Assert.IsNotNull(response.Links.Self);
Assert.AreEqual("https://exampledomain.com/bcl/api/v2/scaAssociations?pageNumber=0&entityType=accountHolder&pageSize=10&entityId=AH3227J223222D5HHM4779X6X", response.Links.Self.VarHref);
Assert.AreEqual(2, response.ItemsTotal);
Assert.AreEqual(1, response.PagesTotal);
Assert.IsNotNull(response.Data);
Assert.AreEqual(2, response.Data.Count);

// Assert first association
var association1 = response.Data[0];
Assert.AreEqual("BSDR11111111111A1AAA1AAAAA1AA1", association1.ScaDeviceId);
Assert.AreEqual("Device 1", association1.ScaDeviceName);
Assert.AreEqual(ScaDeviceType.Ios, association1.ScaDeviceType);
Assert.AreEqual(ScaEntityType.AccountHolder, association1.EntityType);
Assert.AreEqual("AH00000000000000000000001", association1.EntityId);
Assert.AreEqual(AssociationStatus.Active, association1.Status);
Assert.AreEqual(DateTimeOffset.Parse("2025-09-02T14:39:17.232Z"), association1.CreatedAt);

// Assert second association
var association2 = response.Data[1];
Assert.AreEqual("BSDR22222222222B2BBB2BBBBB2BB2", association2.ScaDeviceId);
Assert.AreEqual("Device 2", association2.ScaDeviceName);
Assert.AreEqual(ScaDeviceType.Ios, association2.ScaDeviceType);
Assert.AreEqual(ScaEntityType.AccountHolder, association2.EntityType);
Assert.AreEqual("AH00000000000000000000001", association2.EntityId);
Assert.AreEqual(AssociationStatus.PendingApproval, association2.Status);
Assert.AreEqual(DateTimeOffset.Parse("2025-09-02T14:39:17.232Z"), association2.CreatedAt);
}

[TestMethod]
public async Task Given_RemoveAssociationRequest_Deserialize_Correctly()
{
// Arrange
string json = TestUtilities.GetTestFileContent("mocks/balanceplatform/RemoveAssociationRequest.json");

// Act
var response = JsonSerializer.Deserialize<RemoveAssociationRequest>(json, _jsonSerializerOptionsProvider.Options);

// Assert
Assert.IsNotNull(response);
Assert.AreEqual("AH00000000000000000000001", response.EntityId);
Assert.AreEqual(ScaEntityType.AccountHolder, response.EntityType);
Assert.IsNotNull(response.ScaDeviceIds);
Assert.AreEqual(2, response.ScaDeviceIds.Count);
Assert.AreEqual("BSDR42XV3223223S5N6CDQDGH53M8H", response.ScaDeviceIds[0]);
Assert.AreEqual("BSDR1234567890123456789012345678", response.ScaDeviceIds[1]);
}
}
}
52 changes: 50 additions & 2 deletions Adyen.Test/Checkout/PaymentsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,55 @@ public async Task SessionsAsyncTest()
Assert.IsNotNull(sessionResponse);
Assert.AreEqual("CS0068299CB8DA273A", sessionResponse.Id);
}


[TestMethod]
public async Task AddAdditionalHeadersWithPaymentsServiceTest()
{
// Arrange
var requestOptions = new RequestOptions();
var additionalHeaders = new Dictionary<string, string>
{
{ "X-Custom-Header-For-Payments", "PaymentsValue" },
{ "X-Another-Custom-Header", "AnotherValue" }
};

requestOptions.AddAdditionalHeaders(additionalHeaders);

var createCheckoutSessionRequest = new CreateCheckoutSessionRequest(
amount: new Amount("EUR", 10000L),
merchantAccount: "TestMerchantAccount",
reference: "TestReference",
returnUrl: "http://test-url.com",
channel: CreateCheckoutSessionRequest.ChannelEnum.Web,
countryCode: "NL"
);

RequestOptions capturedRequestOptions = null;
_paymentsService.SessionsAsync(
Arg.Any<CreateCheckoutSessionRequest>(),
Arg.Do<RequestOptions>(ro => capturedRequestOptions = ro),
Arg.Any<CancellationToken>())
.Returns(Task.FromResult<ISessionsApiResponse>(
new PaymentsService.SessionsApiResponse(
Substitute.For<Microsoft.Extensions.Logging.ILogger<PaymentsService.SessionsApiResponse>>(),
new HttpRequestMessage(),
new HttpResponseMessage { StatusCode = HttpStatusCode.OK },
"{}", // Dummy JSON response
"/sessions",
DateTime.UtcNow,
_jsonSerializerOptionsProvider.Options)
));

// Act
await _paymentsService.SessionsAsync(createCheckoutSessionRequest, requestOptions);

// Assert
Assert.IsNotNull(capturedRequestOptions);
Assert.AreEqual(2, capturedRequestOptions.Headers.Count);
Assert.IsTrue(capturedRequestOptions.Headers.ContainsKey("X-Custom-Header-For-Payments"));
Assert.AreEqual("PaymentsValue", capturedRequestOptions.Headers["X-Custom-Header-For-Payments"]);
Assert.IsTrue(capturedRequestOptions.Headers.ContainsKey("X-Another-Custom-Header"));
Assert.AreEqual("AnotherValue", capturedRequestOptions.Headers["X-Another-Custom-Header"]);
}
}

}
24 changes: 20 additions & 4 deletions Adyen.Test/TerminalApi/HeaderRequestTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using System.Linq;
using System.Net.Http;
using Adyen.Constants;
using Adyen.Core.Client.Extensions;
using Adyen.Core.Client.Extensions;
using Adyen.HttpClient;
using Adyen.Model;
using Microsoft.VisualStudio.TestTools.UnitTesting;
Expand Down Expand Up @@ -203,5 +200,24 @@ public void LibraryAnalysisConstantsInHeaderTest()
Assert.IsNotNull(httpWebRequest.Headers.GetValues("adyen-library-version"));
Assert.AreEqual(HttpRequestMessageExtensions.AdyenLibraryVersion, httpWebRequest.Headers.GetValues("adyen-library-version").FirstOrDefault());
}

[TestMethod]
public void AddAdditionalHeadersTest()
{
var requestOptions = new Adyen.Core.Client.RequestOptions();
var additionalHeaders = new Dictionary<string, string>
{
{ "X-Custom-Header-1", "Value1" },
{ "X-Custom-Header-2", "Value2" }
};

requestOptions.AddAdditionalHeaders(additionalHeaders);

Assert.AreEqual(2, requestOptions.Headers.Count);
Assert.IsTrue(requestOptions.Headers.ContainsKey("X-Custom-Header-1"));
Assert.AreEqual("Value1", requestOptions.Headers["X-Custom-Header-1"]);
Assert.IsTrue(requestOptions.Headers.ContainsKey("X-Custom-Header-2"));
Assert.AreEqual("Value2", requestOptions.Headers["X-Custom-Header-2"]);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"status": "active",
"entityType": "accountHolder",
"entityId": "AH00000000000000000000001",
"scaDeviceIds": [
"BSDR42XV3223223S5N6CDQDGH53M8H"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"scaAssociations": [
{
"scaDeviceId": "BSDR42XV3223223S5N6CDQDGH53M8H",
"entityType": "accountHolder",
"entityId": "AH00000000000000000000001",
"status": "active"
}
]
}
29 changes: 29 additions & 0 deletions Adyen.Test/mocks/balanceplatform/ListAssociationsResponse.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"_links": {
"self": {
"href": "https://exampledomain.com/bcl/api/v2/scaAssociations?pageNumber=0&entityType=accountHolder&pageSize=10&entityId=AH3227J223222D5HHM4779X6X"
}
},
"itemsTotal": 2,
"pagesTotal": 1,
"data": [
{
"scaDeviceId": "BSDR11111111111A1AAA1AAAAA1AA1",
"scaDeviceName": "Device 1",
"scaDeviceType": "ios",
"entityType": "accountHolder",
"entityId": "AH00000000000000000000001",
"status": "active",
"createdAt": "2025-09-02T14:39:17.232Z"
},
{
"scaDeviceId": "BSDR22222222222B2BBB2BBBBB2BB2",
"scaDeviceName": "Device 2",
"scaDeviceType": "ios",
"entityType": "accountHolder",
"entityId": "AH00000000000000000000001",
"status": "pendingApproval",
"createdAt": "2025-09-02T14:39:17.232Z"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"entityId": "AH00000000000000000000001",
"entityType": "accountHolder",
"scaDeviceIds": [
"BSDR42XV3223223S5N6CDQDGH53M8H",
"BSDR1234567890123456789012345678"
]
}
Loading