mirror of
https://github.com/bitwarden/server
synced 2025-12-16 00:03:54 +00:00
[PM-24964] Stripe-hosted bank account verification (#6263)
* Implement bank account hosted URL verification with webhook handling notification * Fix tests * Run dotnet format * Remove unused VerifyBankAccount operation * Stephon's feedback * Removing unused test * TEMP: Add logging for deployment check * Run dotnet format * fix test * Revert "fix test" This reverts commitb8743ab3b5. * Revert "Run dotnet format" This reverts commit5c861b0b72. * Revert "TEMP: Add logging for deployment check" This reverts commit0a88acd6a1. * Resolve GetPaymentMethodQuery order of operations
This commit is contained in:
242
test/Billing.Test/Services/SetupIntentSucceededHandlerTests.cs
Normal file
242
test/Billing.Test/Services/SetupIntentSucceededHandlerTests.cs
Normal file
@@ -0,0 +1,242 @@
|
||||
using Bit.Billing.Services;
|
||||
using Bit.Billing.Services.Implementations;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Caches;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using NSubstitute;
|
||||
using Stripe;
|
||||
using Xunit;
|
||||
using Event = Stripe.Event;
|
||||
|
||||
namespace Bit.Billing.Test.Services;
|
||||
|
||||
public class SetupIntentSucceededHandlerTests
|
||||
{
|
||||
private static readonly Event _mockEvent = new() { Id = "evt_test", Type = "setup_intent.succeeded" };
|
||||
private static readonly string[] _expand = ["payment_method"];
|
||||
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly IPushNotificationAdapter _pushNotificationAdapter;
|
||||
private readonly ISetupIntentCache _setupIntentCache;
|
||||
private readonly IStripeAdapter _stripeAdapter;
|
||||
private readonly IStripeEventService _stripeEventService;
|
||||
private readonly SetupIntentSucceededHandler _handler;
|
||||
|
||||
public SetupIntentSucceededHandlerTests()
|
||||
{
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_providerRepository = Substitute.For<IProviderRepository>();
|
||||
_pushNotificationAdapter = Substitute.For<IPushNotificationAdapter>();
|
||||
_setupIntentCache = Substitute.For<ISetupIntentCache>();
|
||||
_stripeAdapter = Substitute.For<IStripeAdapter>();
|
||||
_stripeEventService = Substitute.For<IStripeEventService>();
|
||||
|
||||
_handler = new SetupIntentSucceededHandler(
|
||||
_organizationRepository,
|
||||
_providerRepository,
|
||||
_pushNotificationAdapter,
|
||||
_setupIntentCache,
|
||||
_stripeAdapter,
|
||||
_stripeEventService);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_PaymentMethodNotUSBankAccount_Returns()
|
||||
{
|
||||
// Arrange
|
||||
var setupIntent = CreateSetupIntent(hasUSBankAccount: false);
|
||||
|
||||
_stripeEventService.GetSetupIntent(
|
||||
_mockEvent,
|
||||
true,
|
||||
Arg.Is<List<string>>(options => options.SequenceEqual(_expand)))
|
||||
.Returns(setupIntent);
|
||||
|
||||
// Act
|
||||
await _handler.HandleAsync(_mockEvent);
|
||||
|
||||
// Assert
|
||||
await _setupIntentCache.DidNotReceiveWithAnyArgs().GetSubscriberIdForSetupIntent(Arg.Any<string>());
|
||||
await _stripeAdapter.DidNotReceiveWithAnyArgs().PaymentMethodAttachAsync(
|
||||
Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>());
|
||||
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>());
|
||||
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_NoSubscriberIdInCache_Returns()
|
||||
{
|
||||
// Arrange
|
||||
var setupIntent = CreateSetupIntent();
|
||||
|
||||
_stripeEventService.GetSetupIntent(
|
||||
_mockEvent,
|
||||
true,
|
||||
Arg.Is<List<string>>(options => options.SequenceEqual(_expand)))
|
||||
.Returns(setupIntent);
|
||||
|
||||
_setupIntentCache.GetSubscriberIdForSetupIntent(setupIntent.Id)
|
||||
.Returns((Guid?)null);
|
||||
|
||||
// Act
|
||||
await _handler.HandleAsync(_mockEvent);
|
||||
|
||||
// Assert
|
||||
await _stripeAdapter.DidNotReceiveWithAnyArgs().PaymentMethodAttachAsync(
|
||||
Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>());
|
||||
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>());
|
||||
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_ValidOrganization_AttachesPaymentMethodAndSendsNotification()
|
||||
{
|
||||
// Arrange
|
||||
var organizationId = Guid.NewGuid();
|
||||
var organization = new Organization { Id = organizationId, Name = "Test Org", GatewayCustomerId = "cus_test" };
|
||||
var setupIntent = CreateSetupIntent();
|
||||
|
||||
_stripeEventService.GetSetupIntent(
|
||||
_mockEvent,
|
||||
true,
|
||||
Arg.Is<List<string>>(options => options.SequenceEqual(_expand)))
|
||||
.Returns(setupIntent);
|
||||
|
||||
_setupIntentCache.GetSubscriberIdForSetupIntent(setupIntent.Id)
|
||||
.Returns(organizationId);
|
||||
|
||||
_organizationRepository.GetByIdAsync(organizationId)
|
||||
.Returns(organization);
|
||||
|
||||
// Act
|
||||
await _handler.HandleAsync(_mockEvent);
|
||||
|
||||
// Assert
|
||||
await _stripeAdapter.Received(1).PaymentMethodAttachAsync(
|
||||
"pm_test",
|
||||
Arg.Is<PaymentMethodAttachOptions>(o => o.Customer == organization.GatewayCustomerId));
|
||||
|
||||
await _pushNotificationAdapter.Received(1).NotifyBankAccountVerifiedAsync(organization);
|
||||
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_ValidProvider_AttachesPaymentMethodAndSendsNotification()
|
||||
{
|
||||
// Arrange
|
||||
var providerId = Guid.NewGuid();
|
||||
var provider = new Provider { Id = providerId, Name = "Test Provider", GatewayCustomerId = "cus_test" };
|
||||
var setupIntent = CreateSetupIntent();
|
||||
|
||||
_stripeEventService.GetSetupIntent(
|
||||
_mockEvent,
|
||||
true,
|
||||
Arg.Is<List<string>>(options => options.SequenceEqual(_expand)))
|
||||
.Returns(setupIntent);
|
||||
|
||||
_setupIntentCache.GetSubscriberIdForSetupIntent(setupIntent.Id)
|
||||
.Returns(providerId);
|
||||
|
||||
_organizationRepository.GetByIdAsync(providerId)
|
||||
.Returns((Organization?)null);
|
||||
|
||||
_providerRepository.GetByIdAsync(providerId)
|
||||
.Returns(provider);
|
||||
|
||||
// Act
|
||||
await _handler.HandleAsync(_mockEvent);
|
||||
|
||||
// Assert
|
||||
await _stripeAdapter.Received(1).PaymentMethodAttachAsync(
|
||||
"pm_test",
|
||||
Arg.Is<PaymentMethodAttachOptions>(o => o.Customer == provider.GatewayCustomerId));
|
||||
|
||||
await _pushNotificationAdapter.Received(1).NotifyBankAccountVerifiedAsync(provider);
|
||||
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_OrganizationWithoutGatewayCustomerId_DoesNotAttachPaymentMethod()
|
||||
{
|
||||
// Arrange
|
||||
var organizationId = Guid.NewGuid();
|
||||
var organization = new Organization { Id = organizationId, Name = "Test Org", GatewayCustomerId = null };
|
||||
var setupIntent = CreateSetupIntent();
|
||||
|
||||
_stripeEventService.GetSetupIntent(
|
||||
_mockEvent,
|
||||
true,
|
||||
Arg.Is<List<string>>(options => options.SequenceEqual(_expand)))
|
||||
.Returns(setupIntent);
|
||||
|
||||
_setupIntentCache.GetSubscriberIdForSetupIntent(setupIntent.Id)
|
||||
.Returns(organizationId);
|
||||
|
||||
_organizationRepository.GetByIdAsync(organizationId)
|
||||
.Returns(organization);
|
||||
|
||||
// Act
|
||||
await _handler.HandleAsync(_mockEvent);
|
||||
|
||||
// Assert
|
||||
await _stripeAdapter.DidNotReceiveWithAnyArgs().PaymentMethodAttachAsync(
|
||||
Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>());
|
||||
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>());
|
||||
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task HandleAsync_ProviderWithoutGatewayCustomerId_DoesNotAttachPaymentMethod()
|
||||
{
|
||||
// Arrange
|
||||
var providerId = Guid.NewGuid();
|
||||
var provider = new Provider { Id = providerId, Name = "Test Provider", GatewayCustomerId = null };
|
||||
var setupIntent = CreateSetupIntent();
|
||||
|
||||
_stripeEventService.GetSetupIntent(
|
||||
_mockEvent,
|
||||
true,
|
||||
Arg.Is<List<string>>(options => options.SequenceEqual(_expand)))
|
||||
.Returns(setupIntent);
|
||||
|
||||
_setupIntentCache.GetSubscriberIdForSetupIntent(setupIntent.Id)
|
||||
.Returns(providerId);
|
||||
|
||||
_organizationRepository.GetByIdAsync(providerId)
|
||||
.Returns((Organization?)null);
|
||||
|
||||
_providerRepository.GetByIdAsync(providerId)
|
||||
.Returns(provider);
|
||||
|
||||
// Act
|
||||
await _handler.HandleAsync(_mockEvent);
|
||||
|
||||
// Assert
|
||||
await _stripeAdapter.DidNotReceiveWithAnyArgs().PaymentMethodAttachAsync(
|
||||
Arg.Any<string>(), Arg.Any<PaymentMethodAttachOptions>());
|
||||
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Organization>());
|
||||
await _pushNotificationAdapter.DidNotReceiveWithAnyArgs().NotifyBankAccountVerifiedAsync(Arg.Any<Provider>());
|
||||
}
|
||||
|
||||
private static SetupIntent CreateSetupIntent(bool hasUSBankAccount = true)
|
||||
{
|
||||
var paymentMethod = new PaymentMethod
|
||||
{
|
||||
Id = "pm_test",
|
||||
Type = "us_bank_account",
|
||||
UsBankAccount = hasUSBankAccount ? new PaymentMethodUsBankAccount() : null
|
||||
};
|
||||
|
||||
var setupIntent = new SetupIntent
|
||||
{
|
||||
Id = "seti_test",
|
||||
PaymentMethod = paymentMethod
|
||||
};
|
||||
|
||||
return setupIntent;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
using Bit.Billing.Services;
|
||||
using Bit.Billing.Services.Implementations;
|
||||
using Bit.Billing.Test.Utilities;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Billing.Caches;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Stripe;
|
||||
using Xunit;
|
||||
@@ -11,6 +12,9 @@ namespace Bit.Billing.Test.Services;
|
||||
|
||||
public class StripeEventServiceTests
|
||||
{
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly ISetupIntentCache _setupIntentCache;
|
||||
private readonly IStripeFacade _stripeFacade;
|
||||
private readonly StripeEventService _stripeEventService;
|
||||
|
||||
@@ -20,8 +24,11 @@ public class StripeEventServiceTests
|
||||
var baseServiceUriSettings = new GlobalSettings.BaseServiceUriSettings(globalSettings) { CloudRegion = "US" };
|
||||
globalSettings.BaseServiceUri = baseServiceUriSettings;
|
||||
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
_providerRepository = Substitute.For<IProviderRepository>();
|
||||
_setupIntentCache = Substitute.For<ISetupIntentCache>();
|
||||
_stripeFacade = Substitute.For<IStripeFacade>();
|
||||
_stripeEventService = new StripeEventService(globalSettings, Substitute.For<ILogger<StripeEventService>>(), _stripeFacade);
|
||||
_stripeEventService = new StripeEventService(globalSettings, _organizationRepository, _providerRepository, _setupIntentCache, _stripeFacade);
|
||||
}
|
||||
|
||||
#region GetCharge
|
||||
@@ -29,50 +36,44 @@ public class StripeEventServiceTests
|
||||
public async Task GetCharge_EventNotChargeRelated_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.InvoiceCreated);
|
||||
var stripeEvent = CreateMockEvent("evt_test", "invoice.created", new Invoice { Id = "in_test" });
|
||||
|
||||
// Act
|
||||
var function = async () => await _stripeEventService.GetCharge(stripeEvent);
|
||||
|
||||
// Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(function);
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(async () => await _stripeEventService.GetCharge(stripeEvent));
|
||||
Assert.Equal($"Stripe event with ID '{stripeEvent.Id}' does not have object matching type '{nameof(Charge)}'", exception.Message);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetCharge(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<ChargeGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Any<ChargeGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharge_NotFresh_ReturnsEventCharge()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.ChargeSucceeded);
|
||||
var mockCharge = new Charge { Id = "ch_test", Amount = 1000 };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "charge.succeeded", mockCharge);
|
||||
|
||||
// Act
|
||||
var charge = await _stripeEventService.GetCharge(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.Equivalent(stripeEvent.Data.Object as Charge, charge, true);
|
||||
Assert.Equal(mockCharge.Id, charge.Id);
|
||||
Assert.Equal(mockCharge.Amount, charge.Amount);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetCharge(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<ChargeGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Any<ChargeGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCharge_Fresh_Expand_ReturnsAPICharge()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.ChargeSucceeded);
|
||||
var eventCharge = new Charge { Id = "ch_test", Amount = 1000 };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "charge.succeeded", eventCharge);
|
||||
|
||||
var eventCharge = stripeEvent.Data.Object as Charge;
|
||||
|
||||
var apiCharge = Copy(eventCharge);
|
||||
var apiCharge = new Charge { Id = "ch_test", Amount = 2000 };
|
||||
|
||||
var expand = new List<string> { "customer" };
|
||||
|
||||
@@ -90,9 +91,7 @@ public class StripeEventServiceTests
|
||||
|
||||
await _stripeFacade.Received().GetCharge(
|
||||
apiCharge.Id,
|
||||
Arg.Is<ChargeGetOptions>(options => options.Expand == expand),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Is<ChargeGetOptions>(options => options.Expand == expand));
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -101,50 +100,44 @@ public class StripeEventServiceTests
|
||||
public async Task GetCustomer_EventNotCustomerRelated_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.InvoiceCreated);
|
||||
var stripeEvent = CreateMockEvent("evt_test", "invoice.created", new Invoice { Id = "in_test" });
|
||||
|
||||
// Act
|
||||
var function = async () => await _stripeEventService.GetCustomer(stripeEvent);
|
||||
|
||||
// Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(function);
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(async () => await _stripeEventService.GetCustomer(stripeEvent));
|
||||
Assert.Equal($"Stripe event with ID '{stripeEvent.Id}' does not have object matching type '{nameof(Customer)}'", exception.Message);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetCustomer(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<CustomerGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Any<CustomerGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCustomer_NotFresh_ReturnsEventCustomer()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerUpdated);
|
||||
var mockCustomer = new Customer { Id = "cus_test", Email = "test@example.com" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.updated", mockCustomer);
|
||||
|
||||
// Act
|
||||
var customer = await _stripeEventService.GetCustomer(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.Equivalent(stripeEvent.Data.Object as Customer, customer, true);
|
||||
Assert.Equal(mockCustomer.Id, customer.Id);
|
||||
Assert.Equal(mockCustomer.Email, customer.Email);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetCustomer(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<CustomerGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Any<CustomerGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetCustomer_Fresh_Expand_ReturnsAPICustomer()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerUpdated);
|
||||
var eventCustomer = new Customer { Id = "cus_test", Email = "test@example.com" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.updated", eventCustomer);
|
||||
|
||||
var eventCustomer = stripeEvent.Data.Object as Customer;
|
||||
|
||||
var apiCustomer = Copy(eventCustomer);
|
||||
var apiCustomer = new Customer { Id = "cus_test", Email = "updated@example.com" };
|
||||
|
||||
var expand = new List<string> { "subscriptions" };
|
||||
|
||||
@@ -162,9 +155,7 @@ public class StripeEventServiceTests
|
||||
|
||||
await _stripeFacade.Received().GetCustomer(
|
||||
apiCustomer.Id,
|
||||
Arg.Is<CustomerGetOptions>(options => options.Expand == expand),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Is<CustomerGetOptions>(options => options.Expand == expand));
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -173,50 +164,44 @@ public class StripeEventServiceTests
|
||||
public async Task GetInvoice_EventNotInvoiceRelated_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerUpdated);
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.updated", new Customer { Id = "cus_test" });
|
||||
|
||||
// Act
|
||||
var function = async () => await _stripeEventService.GetInvoice(stripeEvent);
|
||||
|
||||
// Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(function);
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(async () => await _stripeEventService.GetInvoice(stripeEvent));
|
||||
Assert.Equal($"Stripe event with ID '{stripeEvent.Id}' does not have object matching type '{nameof(Invoice)}'", exception.Message);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetInvoice(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<InvoiceGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Any<InvoiceGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetInvoice_NotFresh_ReturnsEventInvoice()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.InvoiceCreated);
|
||||
var mockInvoice = new Invoice { Id = "in_test", AmountDue = 1000 };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "invoice.created", mockInvoice);
|
||||
|
||||
// Act
|
||||
var invoice = await _stripeEventService.GetInvoice(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.Equivalent(stripeEvent.Data.Object as Invoice, invoice, true);
|
||||
Assert.Equal(mockInvoice.Id, invoice.Id);
|
||||
Assert.Equal(mockInvoice.AmountDue, invoice.AmountDue);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetInvoice(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<InvoiceGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Any<InvoiceGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetInvoice_Fresh_Expand_ReturnsAPIInvoice()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.InvoiceCreated);
|
||||
var eventInvoice = new Invoice { Id = "in_test", AmountDue = 1000 };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "invoice.created", eventInvoice);
|
||||
|
||||
var eventInvoice = stripeEvent.Data.Object as Invoice;
|
||||
|
||||
var apiInvoice = Copy(eventInvoice);
|
||||
var apiInvoice = new Invoice { Id = "in_test", AmountDue = 2000 };
|
||||
|
||||
var expand = new List<string> { "customer" };
|
||||
|
||||
@@ -234,9 +219,7 @@ public class StripeEventServiceTests
|
||||
|
||||
await _stripeFacade.Received().GetInvoice(
|
||||
apiInvoice.Id,
|
||||
Arg.Is<InvoiceGetOptions>(options => options.Expand == expand),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Is<InvoiceGetOptions>(options => options.Expand == expand));
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -245,50 +228,44 @@ public class StripeEventServiceTests
|
||||
public async Task GetPaymentMethod_EventNotPaymentMethodRelated_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerUpdated);
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.updated", new Customer { Id = "cus_test" });
|
||||
|
||||
// Act
|
||||
var function = async () => await _stripeEventService.GetPaymentMethod(stripeEvent);
|
||||
|
||||
// Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(function);
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(async () => await _stripeEventService.GetPaymentMethod(stripeEvent));
|
||||
Assert.Equal($"Stripe event with ID '{stripeEvent.Id}' does not have object matching type '{nameof(PaymentMethod)}'", exception.Message);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetPaymentMethod(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<PaymentMethodGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Any<PaymentMethodGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPaymentMethod_NotFresh_ReturnsEventPaymentMethod()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.PaymentMethodAttached);
|
||||
var mockPaymentMethod = new PaymentMethod { Id = "pm_test", Type = "card" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "payment_method.attached", mockPaymentMethod);
|
||||
|
||||
// Act
|
||||
var paymentMethod = await _stripeEventService.GetPaymentMethod(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.Equivalent(stripeEvent.Data.Object as PaymentMethod, paymentMethod, true);
|
||||
Assert.Equal(mockPaymentMethod.Id, paymentMethod.Id);
|
||||
Assert.Equal(mockPaymentMethod.Type, paymentMethod.Type);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetPaymentMethod(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<PaymentMethodGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Any<PaymentMethodGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetPaymentMethod_Fresh_Expand_ReturnsAPIPaymentMethod()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.PaymentMethodAttached);
|
||||
var eventPaymentMethod = new PaymentMethod { Id = "pm_test", Type = "card" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "payment_method.attached", eventPaymentMethod);
|
||||
|
||||
var eventPaymentMethod = stripeEvent.Data.Object as PaymentMethod;
|
||||
|
||||
var apiPaymentMethod = Copy(eventPaymentMethod);
|
||||
var apiPaymentMethod = new PaymentMethod { Id = "pm_test", Type = "card" };
|
||||
|
||||
var expand = new List<string> { "customer" };
|
||||
|
||||
@@ -306,9 +283,7 @@ public class StripeEventServiceTests
|
||||
|
||||
await _stripeFacade.Received().GetPaymentMethod(
|
||||
apiPaymentMethod.Id,
|
||||
Arg.Is<PaymentMethodGetOptions>(options => options.Expand == expand),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Is<PaymentMethodGetOptions>(options => options.Expand == expand));
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -317,50 +292,44 @@ public class StripeEventServiceTests
|
||||
public async Task GetSubscription_EventNotSubscriptionRelated_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerUpdated);
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.updated", new Customer { Id = "cus_test" });
|
||||
|
||||
// Act
|
||||
var function = async () => await _stripeEventService.GetSubscription(stripeEvent);
|
||||
|
||||
// Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(function);
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(async () => await _stripeEventService.GetSubscription(stripeEvent));
|
||||
Assert.Equal($"Stripe event with ID '{stripeEvent.Id}' does not have object matching type '{nameof(Subscription)}'", exception.Message);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetSubscription(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<SubscriptionGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Any<SubscriptionGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSubscription_NotFresh_ReturnsEventSubscription()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerSubscriptionUpdated);
|
||||
var mockSubscription = new Subscription { Id = "sub_test", Status = "active" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.subscription.updated", mockSubscription);
|
||||
|
||||
// Act
|
||||
var subscription = await _stripeEventService.GetSubscription(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.Equivalent(stripeEvent.Data.Object as Subscription, subscription, true);
|
||||
Assert.Equal(mockSubscription.Id, subscription.Id);
|
||||
Assert.Equal(mockSubscription.Status, subscription.Status);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetSubscription(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<SubscriptionGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Any<SubscriptionGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSubscription_Fresh_Expand_ReturnsAPISubscription()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerSubscriptionUpdated);
|
||||
var eventSubscription = new Subscription { Id = "sub_test", Status = "active" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.subscription.updated", eventSubscription);
|
||||
|
||||
var eventSubscription = stripeEvent.Data.Object as Subscription;
|
||||
|
||||
var apiSubscription = Copy(eventSubscription);
|
||||
var apiSubscription = new Subscription { Id = "sub_test", Status = "canceled" };
|
||||
|
||||
var expand = new List<string> { "customer" };
|
||||
|
||||
@@ -378,9 +347,71 @@ public class StripeEventServiceTests
|
||||
|
||||
await _stripeFacade.Received().GetSubscription(
|
||||
apiSubscription.Id,
|
||||
Arg.Is<SubscriptionGetOptions>(options => options.Expand == expand),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
Arg.Is<SubscriptionGetOptions>(options => options.Expand == expand));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetSetupIntent
|
||||
[Fact]
|
||||
public async Task GetSetupIntent_EventNotSetupIntentRelated_ThrowsException()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.updated", new Customer { Id = "cus_test" });
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<Exception>(async () => await _stripeEventService.GetSetupIntent(stripeEvent));
|
||||
Assert.Equal($"Stripe event with ID '{stripeEvent.Id}' does not have object matching type '{nameof(SetupIntent)}'", exception.Message);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetSetupIntent(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<SetupIntentGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSetupIntent_NotFresh_ReturnsEventSetupIntent()
|
||||
{
|
||||
// Arrange
|
||||
var mockSetupIntent = new SetupIntent { Id = "seti_test", Status = "succeeded" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "setup_intent.succeeded", mockSetupIntent);
|
||||
|
||||
// Act
|
||||
var setupIntent = await _stripeEventService.GetSetupIntent(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(mockSetupIntent.Id, setupIntent.Id);
|
||||
Assert.Equal(mockSetupIntent.Status, setupIntent.Status);
|
||||
|
||||
await _stripeFacade.DidNotReceiveWithAnyArgs().GetSetupIntent(
|
||||
Arg.Any<string>(),
|
||||
Arg.Any<SetupIntentGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetSetupIntent_Fresh_Expand_ReturnsAPISetupIntent()
|
||||
{
|
||||
// Arrange
|
||||
var eventSetupIntent = new SetupIntent { Id = "seti_test", Status = "succeeded" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "setup_intent.succeeded", eventSetupIntent);
|
||||
|
||||
var apiSetupIntent = new SetupIntent { Id = "seti_test", Status = "requires_action" };
|
||||
|
||||
var expand = new List<string> { "customer" };
|
||||
|
||||
_stripeFacade.GetSetupIntent(
|
||||
apiSetupIntent.Id,
|
||||
Arg.Is<SetupIntentGetOptions>(options => options.Expand == expand))
|
||||
.Returns(apiSetupIntent);
|
||||
|
||||
// Act
|
||||
var setupIntent = await _stripeEventService.GetSetupIntent(stripeEvent, true, expand);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(apiSetupIntent, setupIntent);
|
||||
Assert.NotSame(eventSetupIntent, setupIntent);
|
||||
|
||||
await _stripeFacade.Received().GetSetupIntent(
|
||||
apiSetupIntent.Id,
|
||||
Arg.Is<SetupIntentGetOptions>(options => options.Expand == expand));
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -389,18 +420,16 @@ public class StripeEventServiceTests
|
||||
public async Task ValidateCloudRegion_SubscriptionUpdated_Success()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerSubscriptionUpdated);
|
||||
var mockSubscription = new Subscription { Id = "sub_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.subscription.updated", mockSubscription);
|
||||
|
||||
var subscription = Copy(stripeEvent.Data.Object as Subscription);
|
||||
|
||||
var customer = await GetCustomerAsync();
|
||||
|
||||
subscription.Customer = customer;
|
||||
var customer = CreateMockCustomer();
|
||||
mockSubscription.Customer = customer;
|
||||
|
||||
_stripeFacade.GetSubscription(
|
||||
subscription.Id,
|
||||
mockSubscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>())
|
||||
.Returns(subscription);
|
||||
.Returns(mockSubscription);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
@@ -409,28 +438,24 @@ public class StripeEventServiceTests
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _stripeFacade.Received(1).GetSubscription(
|
||||
subscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
mockSubscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_ChargeSucceeded_Success()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.ChargeSucceeded);
|
||||
var mockCharge = new Charge { Id = "ch_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "charge.succeeded", mockCharge);
|
||||
|
||||
var charge = Copy(stripeEvent.Data.Object as Charge);
|
||||
|
||||
var customer = await GetCustomerAsync();
|
||||
|
||||
charge.Customer = customer;
|
||||
var customer = CreateMockCustomer();
|
||||
mockCharge.Customer = customer;
|
||||
|
||||
_stripeFacade.GetCharge(
|
||||
charge.Id,
|
||||
mockCharge.Id,
|
||||
Arg.Any<ChargeGetOptions>())
|
||||
.Returns(charge);
|
||||
.Returns(mockCharge);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
@@ -439,24 +464,21 @@ public class StripeEventServiceTests
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _stripeFacade.Received(1).GetCharge(
|
||||
charge.Id,
|
||||
Arg.Any<ChargeGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
mockCharge.Id,
|
||||
Arg.Any<ChargeGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_UpcomingInvoice_Success()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.InvoiceUpcoming);
|
||||
var mockInvoice = new Invoice { Id = "in_test", CustomerId = "cus_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "invoice.upcoming", mockInvoice);
|
||||
|
||||
var invoice = Copy(stripeEvent.Data.Object as Invoice);
|
||||
|
||||
var customer = await GetCustomerAsync();
|
||||
var customer = CreateMockCustomer();
|
||||
|
||||
_stripeFacade.GetCustomer(
|
||||
invoice.CustomerId,
|
||||
mockInvoice.CustomerId,
|
||||
Arg.Any<CustomerGetOptions>())
|
||||
.Returns(customer);
|
||||
|
||||
@@ -467,28 +489,24 @@ public class StripeEventServiceTests
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _stripeFacade.Received(1).GetCustomer(
|
||||
invoice.CustomerId,
|
||||
Arg.Any<CustomerGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
mockInvoice.CustomerId,
|
||||
Arg.Any<CustomerGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_InvoiceCreated_Success()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.InvoiceCreated);
|
||||
var mockInvoice = new Invoice { Id = "in_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "invoice.created", mockInvoice);
|
||||
|
||||
var invoice = Copy(stripeEvent.Data.Object as Invoice);
|
||||
|
||||
var customer = await GetCustomerAsync();
|
||||
|
||||
invoice.Customer = customer;
|
||||
var customer = CreateMockCustomer();
|
||||
mockInvoice.Customer = customer;
|
||||
|
||||
_stripeFacade.GetInvoice(
|
||||
invoice.Id,
|
||||
mockInvoice.Id,
|
||||
Arg.Any<InvoiceGetOptions>())
|
||||
.Returns(invoice);
|
||||
.Returns(mockInvoice);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
@@ -497,28 +515,24 @@ public class StripeEventServiceTests
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _stripeFacade.Received(1).GetInvoice(
|
||||
invoice.Id,
|
||||
Arg.Any<InvoiceGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
mockInvoice.Id,
|
||||
Arg.Any<InvoiceGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_PaymentMethodAttached_Success()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.PaymentMethodAttached);
|
||||
var mockPaymentMethod = new PaymentMethod { Id = "pm_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "payment_method.attached", mockPaymentMethod);
|
||||
|
||||
var paymentMethod = Copy(stripeEvent.Data.Object as PaymentMethod);
|
||||
|
||||
var customer = await GetCustomerAsync();
|
||||
|
||||
paymentMethod.Customer = customer;
|
||||
var customer = CreateMockCustomer();
|
||||
mockPaymentMethod.Customer = customer;
|
||||
|
||||
_stripeFacade.GetPaymentMethod(
|
||||
paymentMethod.Id,
|
||||
mockPaymentMethod.Id,
|
||||
Arg.Any<PaymentMethodGetOptions>())
|
||||
.Returns(paymentMethod);
|
||||
.Returns(mockPaymentMethod);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
@@ -527,24 +541,21 @@ public class StripeEventServiceTests
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _stripeFacade.Received(1).GetPaymentMethod(
|
||||
paymentMethod.Id,
|
||||
Arg.Any<PaymentMethodGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
mockPaymentMethod.Id,
|
||||
Arg.Any<PaymentMethodGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_CustomerUpdated_Success()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerUpdated);
|
||||
|
||||
var customer = Copy(stripeEvent.Data.Object as Customer);
|
||||
var mockCustomer = CreateMockCustomer();
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.updated", mockCustomer);
|
||||
|
||||
_stripeFacade.GetCustomer(
|
||||
customer.Id,
|
||||
mockCustomer.Id,
|
||||
Arg.Any<CustomerGetOptions>())
|
||||
.Returns(customer);
|
||||
.Returns(mockCustomer);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
@@ -553,29 +564,24 @@ public class StripeEventServiceTests
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _stripeFacade.Received(1).GetCustomer(
|
||||
customer.Id,
|
||||
Arg.Any<CustomerGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
mockCustomer.Id,
|
||||
Arg.Any<CustomerGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_MetadataNull_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerSubscriptionUpdated);
|
||||
var mockSubscription = new Subscription { Id = "sub_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.subscription.updated", mockSubscription);
|
||||
|
||||
var subscription = Copy(stripeEvent.Data.Object as Subscription);
|
||||
|
||||
var customer = await GetCustomerAsync();
|
||||
customer.Metadata = null;
|
||||
|
||||
subscription.Customer = customer;
|
||||
var customer = new Customer { Id = "cus_test", Metadata = null };
|
||||
mockSubscription.Customer = customer;
|
||||
|
||||
_stripeFacade.GetSubscription(
|
||||
subscription.Id,
|
||||
mockSubscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>())
|
||||
.Returns(subscription);
|
||||
.Returns(mockSubscription);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
@@ -584,29 +590,24 @@ public class StripeEventServiceTests
|
||||
Assert.False(cloudRegionValid);
|
||||
|
||||
await _stripeFacade.Received(1).GetSubscription(
|
||||
subscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
mockSubscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_MetadataNoRegion_DefaultUS_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerSubscriptionUpdated);
|
||||
var mockSubscription = new Subscription { Id = "sub_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.subscription.updated", mockSubscription);
|
||||
|
||||
var subscription = Copy(stripeEvent.Data.Object as Subscription);
|
||||
|
||||
var customer = await GetCustomerAsync();
|
||||
customer.Metadata = new Dictionary<string, string>();
|
||||
|
||||
subscription.Customer = customer;
|
||||
var customer = new Customer { Id = "cus_test", Metadata = new Dictionary<string, string>() };
|
||||
mockSubscription.Customer = customer;
|
||||
|
||||
_stripeFacade.GetSubscription(
|
||||
subscription.Id,
|
||||
mockSubscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>())
|
||||
.Returns(subscription);
|
||||
.Returns(mockSubscription);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
@@ -615,32 +616,28 @@ public class StripeEventServiceTests
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _stripeFacade.Received(1).GetSubscription(
|
||||
subscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
mockSubscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_MetadataMiscasedRegion_ReturnsTrue()
|
||||
public async Task ValidateCloudRegion_MetadataIncorrectlyCasedRegion_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var stripeEvent = await StripeTestEvents.GetAsync(StripeEventType.CustomerSubscriptionUpdated);
|
||||
var mockSubscription = new Subscription { Id = "sub_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "customer.subscription.updated", mockSubscription);
|
||||
|
||||
var subscription = Copy(stripeEvent.Data.Object as Subscription);
|
||||
|
||||
var customer = await GetCustomerAsync();
|
||||
customer.Metadata = new Dictionary<string, string>
|
||||
var customer = new Customer
|
||||
{
|
||||
{ "Region", "US" }
|
||||
Id = "cus_test",
|
||||
Metadata = new Dictionary<string, string> { { "Region", "US" } }
|
||||
};
|
||||
|
||||
subscription.Customer = customer;
|
||||
mockSubscription.Customer = customer;
|
||||
|
||||
_stripeFacade.GetSubscription(
|
||||
subscription.Id,
|
||||
mockSubscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>())
|
||||
.Returns(subscription);
|
||||
.Returns(mockSubscription);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
@@ -649,31 +646,209 @@ public class StripeEventServiceTests
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _stripeFacade.Received(1).GetSubscription(
|
||||
subscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>(),
|
||||
Arg.Any<RequestOptions>(),
|
||||
Arg.Any<CancellationToken>());
|
||||
mockSubscription.Id,
|
||||
Arg.Any<SubscriptionGetOptions>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_SetupIntentSucceeded_OrganizationCustomer_Success()
|
||||
{
|
||||
// Arrange
|
||||
var mockSetupIntent = new SetupIntent { Id = "seti_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "setup_intent.succeeded", mockSetupIntent);
|
||||
var organizationId = Guid.NewGuid();
|
||||
var organizationCustomerId = "cus_org_test";
|
||||
|
||||
var mockOrganization = new Core.AdminConsole.Entities.Organization
|
||||
{
|
||||
Id = organizationId,
|
||||
GatewayCustomerId = organizationCustomerId
|
||||
};
|
||||
var customer = CreateMockCustomer();
|
||||
|
||||
_setupIntentCache.GetSubscriberIdForSetupIntent(mockSetupIntent.Id)
|
||||
.Returns(organizationId);
|
||||
|
||||
_organizationRepository.GetByIdAsync(organizationId)
|
||||
.Returns(mockOrganization);
|
||||
|
||||
_stripeFacade.GetCustomer(organizationCustomerId)
|
||||
.Returns(customer);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _setupIntentCache.Received(1).GetSubscriberIdForSetupIntent(mockSetupIntent.Id);
|
||||
await _organizationRepository.Received(1).GetByIdAsync(organizationId);
|
||||
await _stripeFacade.Received(1).GetCustomer(organizationCustomerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_SetupIntentSucceeded_ProviderCustomer_Success()
|
||||
{
|
||||
// Arrange
|
||||
var mockSetupIntent = new SetupIntent { Id = "seti_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "setup_intent.succeeded", mockSetupIntent);
|
||||
var providerId = Guid.NewGuid();
|
||||
var providerCustomerId = "cus_provider_test";
|
||||
|
||||
var mockProvider = new Core.AdminConsole.Entities.Provider.Provider
|
||||
{
|
||||
Id = providerId,
|
||||
GatewayCustomerId = providerCustomerId
|
||||
};
|
||||
var customer = CreateMockCustomer();
|
||||
|
||||
_setupIntentCache.GetSubscriberIdForSetupIntent(mockSetupIntent.Id)
|
||||
.Returns(providerId);
|
||||
|
||||
_organizationRepository.GetByIdAsync(providerId)
|
||||
.Returns((Core.AdminConsole.Entities.Organization?)null);
|
||||
|
||||
_providerRepository.GetByIdAsync(providerId)
|
||||
.Returns(mockProvider);
|
||||
|
||||
_stripeFacade.GetCustomer(providerCustomerId)
|
||||
.Returns(customer);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _setupIntentCache.Received(1).GetSubscriberIdForSetupIntent(mockSetupIntent.Id);
|
||||
await _organizationRepository.Received(1).GetByIdAsync(providerId);
|
||||
await _providerRepository.Received(1).GetByIdAsync(providerId);
|
||||
await _stripeFacade.Received(1).GetCustomer(providerCustomerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_SetupIntentSucceeded_NoSubscriberIdInCache_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var mockSetupIntent = new SetupIntent { Id = "seti_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "setup_intent.succeeded", mockSetupIntent);
|
||||
|
||||
_setupIntentCache.GetSubscriberIdForSetupIntent(mockSetupIntent.Id)
|
||||
.Returns((Guid?)null);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.False(cloudRegionValid);
|
||||
|
||||
await _setupIntentCache.Received(1).GetSubscriberIdForSetupIntent(mockSetupIntent.Id);
|
||||
await _organizationRepository.DidNotReceiveWithAnyArgs().GetByIdAsync(Arg.Any<Guid>());
|
||||
await _providerRepository.DidNotReceiveWithAnyArgs().GetByIdAsync(Arg.Any<Guid>());
|
||||
await _stripeFacade.DidNotReceive().GetCustomer(Arg.Any<string>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_SetupIntentSucceeded_OrganizationWithoutGatewayCustomerId_ChecksProvider()
|
||||
{
|
||||
// Arrange
|
||||
var mockSetupIntent = new SetupIntent { Id = "seti_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "setup_intent.succeeded", mockSetupIntent);
|
||||
var subscriberId = Guid.NewGuid();
|
||||
var providerCustomerId = "cus_provider_test";
|
||||
|
||||
var mockOrganizationWithoutCustomerId = new Core.AdminConsole.Entities.Organization
|
||||
{
|
||||
Id = subscriberId,
|
||||
GatewayCustomerId = null
|
||||
};
|
||||
|
||||
var mockProvider = new Core.AdminConsole.Entities.Provider.Provider
|
||||
{
|
||||
Id = subscriberId,
|
||||
GatewayCustomerId = providerCustomerId
|
||||
};
|
||||
var customer = CreateMockCustomer();
|
||||
|
||||
_setupIntentCache.GetSubscriberIdForSetupIntent(mockSetupIntent.Id)
|
||||
.Returns(subscriberId);
|
||||
|
||||
_organizationRepository.GetByIdAsync(subscriberId)
|
||||
.Returns(mockOrganizationWithoutCustomerId);
|
||||
|
||||
_providerRepository.GetByIdAsync(subscriberId)
|
||||
.Returns(mockProvider);
|
||||
|
||||
_stripeFacade.GetCustomer(providerCustomerId)
|
||||
.Returns(customer);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.True(cloudRegionValid);
|
||||
|
||||
await _setupIntentCache.Received(1).GetSubscriberIdForSetupIntent(mockSetupIntent.Id);
|
||||
await _organizationRepository.Received(1).GetByIdAsync(subscriberId);
|
||||
await _providerRepository.Received(1).GetByIdAsync(subscriberId);
|
||||
await _stripeFacade.Received(1).GetCustomer(providerCustomerId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ValidateCloudRegion_SetupIntentSucceeded_ProviderWithoutGatewayCustomerId_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var mockSetupIntent = new SetupIntent { Id = "seti_test" };
|
||||
var stripeEvent = CreateMockEvent("evt_test", "setup_intent.succeeded", mockSetupIntent);
|
||||
var subscriberId = Guid.NewGuid();
|
||||
|
||||
var mockProviderWithoutCustomerId = new Core.AdminConsole.Entities.Provider.Provider
|
||||
{
|
||||
Id = subscriberId,
|
||||
GatewayCustomerId = null
|
||||
};
|
||||
|
||||
_setupIntentCache.GetSubscriberIdForSetupIntent(mockSetupIntent.Id)
|
||||
.Returns(subscriberId);
|
||||
|
||||
_organizationRepository.GetByIdAsync(subscriberId)
|
||||
.Returns((Core.AdminConsole.Entities.Organization?)null);
|
||||
|
||||
_providerRepository.GetByIdAsync(subscriberId)
|
||||
.Returns(mockProviderWithoutCustomerId);
|
||||
|
||||
// Act
|
||||
var cloudRegionValid = await _stripeEventService.ValidateCloudRegion(stripeEvent);
|
||||
|
||||
// Assert
|
||||
Assert.False(cloudRegionValid);
|
||||
|
||||
await _setupIntentCache.Received(1).GetSubscriberIdForSetupIntent(mockSetupIntent.Id);
|
||||
await _organizationRepository.Received(1).GetByIdAsync(subscriberId);
|
||||
await _providerRepository.Received(1).GetByIdAsync(subscriberId);
|
||||
await _stripeFacade.DidNotReceive().GetCustomer(Arg.Any<string>());
|
||||
}
|
||||
#endregion
|
||||
|
||||
private static T Copy<T>(T input)
|
||||
private static Event CreateMockEvent<T>(string id, string type, T dataObject) where T : IStripeEntity
|
||||
{
|
||||
var copy = (T)Activator.CreateInstance(typeof(T));
|
||||
|
||||
var properties = input.GetType().GetProperties();
|
||||
|
||||
foreach (var property in properties)
|
||||
return new Event
|
||||
{
|
||||
var value = property.GetValue(input);
|
||||
copy!
|
||||
.GetType()
|
||||
.GetProperty(property.Name)!
|
||||
.SetValue(copy, value);
|
||||
}
|
||||
|
||||
return copy;
|
||||
Id = id,
|
||||
Type = type,
|
||||
Data = new EventData
|
||||
{
|
||||
Object = (IHasObject)dataObject
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static async Task<Customer> GetCustomerAsync()
|
||||
=> (await StripeTestEvents.GetAsync(StripeEventType.CustomerUpdated)).Data.Object as Customer;
|
||||
private static Customer CreateMockCustomer()
|
||||
{
|
||||
return new Customer
|
||||
{
|
||||
Id = "cus_test",
|
||||
Metadata = new Dictionary<string, string> { { "region", "US" } }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Billing.Models.StaticStore.Plans;
|
||||
using Bit.Core.Billing.Pricing;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -33,7 +32,6 @@ public class SubscriptionUpdatedHandlerTests
|
||||
private readonly IStripeFacade _stripeFacade;
|
||||
private readonly IOrganizationSponsorshipRenewCommand _organizationSponsorshipRenewCommand;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IPushNotificationService _pushNotificationService;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IOrganizationEnableCommand _organizationEnableCommand;
|
||||
private readonly IOrganizationDisableCommand _organizationDisableCommand;
|
||||
@@ -42,6 +40,7 @@ public class SubscriptionUpdatedHandlerTests
|
||||
private readonly IProviderRepository _providerRepository;
|
||||
private readonly IProviderService _providerService;
|
||||
private readonly IScheduler _scheduler;
|
||||
private readonly IPushNotificationAdapter _pushNotificationAdapter;
|
||||
private readonly SubscriptionUpdatedHandler _sut;
|
||||
|
||||
public SubscriptionUpdatedHandlerTests()
|
||||
@@ -53,7 +52,6 @@ public class SubscriptionUpdatedHandlerTests
|
||||
_organizationSponsorshipRenewCommand = Substitute.For<IOrganizationSponsorshipRenewCommand>();
|
||||
_userService = Substitute.For<IUserService>();
|
||||
_providerService = Substitute.For<IProviderService>();
|
||||
_pushNotificationService = Substitute.For<IPushNotificationService>();
|
||||
_organizationRepository = Substitute.For<IOrganizationRepository>();
|
||||
var schedulerFactory = Substitute.For<ISchedulerFactory>();
|
||||
_organizationEnableCommand = Substitute.For<IOrganizationEnableCommand>();
|
||||
@@ -64,6 +62,7 @@ public class SubscriptionUpdatedHandlerTests
|
||||
_providerService = Substitute.For<IProviderService>();
|
||||
var logger = Substitute.For<ILogger<SubscriptionUpdatedHandler>>();
|
||||
_scheduler = Substitute.For<IScheduler>();
|
||||
_pushNotificationAdapter = Substitute.For<IPushNotificationAdapter>();
|
||||
|
||||
schedulerFactory.GetScheduler().Returns(_scheduler);
|
||||
|
||||
@@ -74,7 +73,6 @@ public class SubscriptionUpdatedHandlerTests
|
||||
_stripeFacade,
|
||||
_organizationSponsorshipRenewCommand,
|
||||
_userService,
|
||||
_pushNotificationService,
|
||||
_organizationRepository,
|
||||
schedulerFactory,
|
||||
_organizationEnableCommand,
|
||||
@@ -83,7 +81,8 @@ public class SubscriptionUpdatedHandlerTests
|
||||
_featureService,
|
||||
_providerRepository,
|
||||
_providerService,
|
||||
logger);
|
||||
logger,
|
||||
_pushNotificationAdapter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -540,8 +539,8 @@ public class SubscriptionUpdatedHandlerTests
|
||||
.EnableAsync(organizationId);
|
||||
await _organizationService.Received(1)
|
||||
.UpdateExpirationDateAsync(organizationId, currentPeriodEnd);
|
||||
await _pushNotificationService.Received(1)
|
||||
.PushSyncOrganizationStatusAsync(organization);
|
||||
await _pushNotificationAdapter.Received(1)
|
||||
.NotifyEnabledChangedAsync(organization);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -71,7 +71,7 @@ public class GetOrganizationWarningsQueryTests
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().EditSubscription(organization.Id).Returns(true);
|
||||
sutProvider.GetDependency<ISetupIntentCache>().Get(organization.Id).Returns((string?)null);
|
||||
sutProvider.GetDependency<ISetupIntentCache>().GetSetupIntentIdForSubscriber(organization.Id).Returns((string?)null);
|
||||
|
||||
var response = await sutProvider.Sut.Run(organization);
|
||||
|
||||
@@ -109,7 +109,7 @@ public class GetOrganizationWarningsQueryTests
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>().EditSubscription(organization.Id).Returns(true);
|
||||
sutProvider.GetDependency<ISetupIntentCache>().Get(organization.Id).Returns(setupIntentId);
|
||||
sutProvider.GetDependency<ISetupIntentCache>().GetSetupIntentIdForSubscriber(organization.Id).Returns(setupIntentId);
|
||||
sutProvider.GetDependency<IStripeAdapter>().SetupIntentGet(setupIntentId, Arg.Is<SetupIntentGetOptions>(
|
||||
options => options.Expand.Contains("payment_method"))).Returns(new SetupIntent
|
||||
{
|
||||
|
||||
@@ -74,7 +74,10 @@ public class UpdatePaymentMethodCommandTests
|
||||
},
|
||||
NextAction = new SetupIntentNextAction
|
||||
{
|
||||
VerifyWithMicrodeposits = new SetupIntentNextActionVerifyWithMicrodeposits()
|
||||
VerifyWithMicrodeposits = new SetupIntentNextActionVerifyWithMicrodeposits
|
||||
{
|
||||
HostedVerificationUrl = "https://example.com"
|
||||
}
|
||||
},
|
||||
Status = "requires_action"
|
||||
};
|
||||
@@ -95,7 +98,7 @@ public class UpdatePaymentMethodCommandTests
|
||||
var maskedBankAccount = maskedPaymentMethod.AsT0;
|
||||
Assert.Equal("Chase", maskedBankAccount.BankName);
|
||||
Assert.Equal("9999", maskedBankAccount.Last4);
|
||||
Assert.False(maskedBankAccount.Verified);
|
||||
Assert.Equal("https://example.com", maskedBankAccount.HostedVerificationUrl);
|
||||
|
||||
await _setupIntentCache.Received(1).Set(organization.Id, setupIntent.Id);
|
||||
}
|
||||
@@ -133,7 +136,10 @@ public class UpdatePaymentMethodCommandTests
|
||||
},
|
||||
NextAction = new SetupIntentNextAction
|
||||
{
|
||||
VerifyWithMicrodeposits = new SetupIntentNextActionVerifyWithMicrodeposits()
|
||||
VerifyWithMicrodeposits = new SetupIntentNextActionVerifyWithMicrodeposits
|
||||
{
|
||||
HostedVerificationUrl = "https://example.com"
|
||||
}
|
||||
},
|
||||
Status = "requires_action"
|
||||
};
|
||||
@@ -154,7 +160,7 @@ public class UpdatePaymentMethodCommandTests
|
||||
var maskedBankAccount = maskedPaymentMethod.AsT0;
|
||||
Assert.Equal("Chase", maskedBankAccount.BankName);
|
||||
Assert.Equal("9999", maskedBankAccount.Last4);
|
||||
Assert.False(maskedBankAccount.Verified);
|
||||
Assert.Equal("https://example.com", maskedBankAccount.HostedVerificationUrl);
|
||||
|
||||
await _subscriberService.Received(1).CreateStripeCustomer(organization);
|
||||
|
||||
@@ -199,7 +205,10 @@ public class UpdatePaymentMethodCommandTests
|
||||
},
|
||||
NextAction = new SetupIntentNextAction
|
||||
{
|
||||
VerifyWithMicrodeposits = new SetupIntentNextActionVerifyWithMicrodeposits()
|
||||
VerifyWithMicrodeposits = new SetupIntentNextActionVerifyWithMicrodeposits
|
||||
{
|
||||
HostedVerificationUrl = "https://example.com"
|
||||
}
|
||||
},
|
||||
Status = "requires_action"
|
||||
};
|
||||
@@ -220,7 +229,7 @@ public class UpdatePaymentMethodCommandTests
|
||||
var maskedBankAccount = maskedPaymentMethod.AsT0;
|
||||
Assert.Equal("Chase", maskedBankAccount.BankName);
|
||||
Assert.Equal("9999", maskedBankAccount.Last4);
|
||||
Assert.False(maskedBankAccount.Verified);
|
||||
Assert.Equal("https://example.com", maskedBankAccount.HostedVerificationUrl);
|
||||
|
||||
await _setupIntentCache.Received(1).Set(organization.Id, setupIntent.Id);
|
||||
await _stripeAdapter.Received(1).CustomerUpdateAsync(customer.Id, Arg.Is<CustomerUpdateOptions>(options =>
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.Billing.Caches;
|
||||
using Bit.Core.Billing.Payment.Commands;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Test.Billing.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Stripe;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Billing.Payment.Commands;
|
||||
|
||||
public class VerifyBankAccountCommandTests
|
||||
{
|
||||
private readonly ISetupIntentCache _setupIntentCache = Substitute.For<ISetupIntentCache>();
|
||||
private readonly IStripeAdapter _stripeAdapter = Substitute.For<IStripeAdapter>();
|
||||
private readonly VerifyBankAccountCommand _command;
|
||||
|
||||
public VerifyBankAccountCommandTests()
|
||||
{
|
||||
_command = new VerifyBankAccountCommand(
|
||||
Substitute.For<ILogger<VerifyBankAccountCommand>>(),
|
||||
_setupIntentCache,
|
||||
_stripeAdapter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Run_MakesCorrectInvocations_ReturnsMaskedBankAccount()
|
||||
{
|
||||
var organization = new Organization
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
GatewayCustomerId = "cus_123"
|
||||
};
|
||||
|
||||
const string setupIntentId = "seti_123";
|
||||
|
||||
_setupIntentCache.Get(organization.Id).Returns(setupIntentId);
|
||||
|
||||
var setupIntent = new SetupIntent
|
||||
{
|
||||
Id = setupIntentId,
|
||||
PaymentMethodId = "pm_123",
|
||||
PaymentMethod =
|
||||
new PaymentMethod
|
||||
{
|
||||
Id = "pm_123",
|
||||
Type = "us_bank_account",
|
||||
UsBankAccount = new PaymentMethodUsBankAccount { BankName = "Chase", Last4 = "9999" }
|
||||
},
|
||||
NextAction = new SetupIntentNextAction
|
||||
{
|
||||
VerifyWithMicrodeposits = new SetupIntentNextActionVerifyWithMicrodeposits()
|
||||
},
|
||||
Status = "requires_action"
|
||||
};
|
||||
|
||||
_stripeAdapter.SetupIntentGet(setupIntentId,
|
||||
Arg.Is<SetupIntentGetOptions>(options => options.HasExpansions("payment_method"))).Returns(setupIntent);
|
||||
|
||||
_stripeAdapter.PaymentMethodAttachAsync(setupIntent.PaymentMethodId,
|
||||
Arg.Is<PaymentMethodAttachOptions>(options => options.Customer == organization.GatewayCustomerId))
|
||||
.Returns(setupIntent.PaymentMethod);
|
||||
|
||||
var result = await _command.Run(organization, "DESCRIPTOR_CODE");
|
||||
|
||||
Assert.True(result.IsT0);
|
||||
var maskedPaymentMethod = result.AsT0;
|
||||
Assert.True(maskedPaymentMethod.IsT0);
|
||||
var maskedBankAccount = maskedPaymentMethod.AsT0;
|
||||
Assert.Equal("Chase", maskedBankAccount.BankName);
|
||||
Assert.Equal("9999", maskedBankAccount.Last4);
|
||||
Assert.True(maskedBankAccount.Verified);
|
||||
|
||||
await _stripeAdapter.Received(1).SetupIntentVerifyMicroDeposit(setupIntent.Id,
|
||||
Arg.Is<SetupIntentVerifyMicrodepositsOptions>(options => options.DescriptorCode == "DESCRIPTOR_CODE"));
|
||||
|
||||
await _stripeAdapter.Received(1).CustomerUpdateAsync(organization.GatewayCustomerId, Arg.Is<CustomerUpdateOptions>(
|
||||
options => options.InvoiceSettings.DefaultPaymentMethod == setupIntent.PaymentMethodId));
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class MaskedPaymentMethodTests
|
||||
{
|
||||
BankName = "Chase",
|
||||
Last4 = "9999",
|
||||
Verified = true
|
||||
HostedVerificationUrl = "https://example.com"
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(input);
|
||||
@@ -32,7 +32,7 @@ public class MaskedPaymentMethodTests
|
||||
{
|
||||
BankName = "Chase",
|
||||
Last4 = "9999",
|
||||
Verified = true
|
||||
HostedVerificationUrl = "https://example.com"
|
||||
};
|
||||
|
||||
var jsonSerializerOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
|
||||
|
||||
@@ -108,7 +108,7 @@ public class GetPaymentMethodQueryTests
|
||||
var maskedBankAccount = maskedPaymentMethod.AsT0;
|
||||
Assert.Equal("Chase", maskedBankAccount.BankName);
|
||||
Assert.Equal("9999", maskedBankAccount.Last4);
|
||||
Assert.True(maskedBankAccount.Verified);
|
||||
Assert.Null(maskedBankAccount.HostedVerificationUrl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -142,7 +142,7 @@ public class GetPaymentMethodQueryTests
|
||||
var maskedBankAccount = maskedPaymentMethod.AsT0;
|
||||
Assert.Equal("Chase", maskedBankAccount.BankName);
|
||||
Assert.Equal("9999", maskedBankAccount.Last4);
|
||||
Assert.True(maskedBankAccount.Verified);
|
||||
Assert.Null(maskedBankAccount.HostedVerificationUrl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -163,7 +163,7 @@ public class GetPaymentMethodQueryTests
|
||||
Arg.Is<CustomerGetOptions>(options =>
|
||||
options.HasExpansions("default_source", "invoice_settings.default_payment_method"))).Returns(customer);
|
||||
|
||||
_setupIntentCache.Get(organization.Id).Returns("seti_123");
|
||||
_setupIntentCache.GetSetupIntentIdForSubscriber(organization.Id).Returns("seti_123");
|
||||
|
||||
_stripeAdapter
|
||||
.SetupIntentGet("seti_123",
|
||||
@@ -177,7 +177,10 @@ public class GetPaymentMethodQueryTests
|
||||
},
|
||||
NextAction = new SetupIntentNextAction
|
||||
{
|
||||
VerifyWithMicrodeposits = new SetupIntentNextActionVerifyWithMicrodeposits()
|
||||
VerifyWithMicrodeposits = new SetupIntentNextActionVerifyWithMicrodeposits
|
||||
{
|
||||
HostedVerificationUrl = "https://example.com"
|
||||
}
|
||||
},
|
||||
Status = "requires_action"
|
||||
});
|
||||
@@ -189,7 +192,7 @@ public class GetPaymentMethodQueryTests
|
||||
var maskedBankAccount = maskedPaymentMethod.AsT0;
|
||||
Assert.Equal("Chase", maskedBankAccount.BankName);
|
||||
Assert.Equal("9999", maskedBankAccount.Last4);
|
||||
Assert.False(maskedBankAccount.Verified);
|
||||
Assert.Equal("https://example.com", maskedBankAccount.HostedVerificationUrl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -670,7 +670,7 @@ public class SubscriberServiceTests
|
||||
}
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<ISetupIntentCache>().Get(provider.Id).Returns(setupIntent.Id);
|
||||
sutProvider.GetDependency<ISetupIntentCache>().GetSetupIntentIdForSubscriber(provider.Id).Returns(setupIntent.Id);
|
||||
|
||||
sutProvider.GetDependency<IStripeAdapter>().SetupIntentGet(setupIntent.Id,
|
||||
Arg.Is<SetupIntentGetOptions>(options => options.Expand.Contains("payment_method"))).Returns(setupIntent);
|
||||
@@ -1876,7 +1876,7 @@ public class SubscriberServiceTests
|
||||
PaymentMethodId = "payment_method_id"
|
||||
};
|
||||
|
||||
sutProvider.GetDependency<ISetupIntentCache>().Get(provider.Id).Returns(setupIntent.Id);
|
||||
sutProvider.GetDependency<ISetupIntentCache>().GetSetupIntentIdForSubscriber(provider.Id).Returns(setupIntent.Id);
|
||||
|
||||
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
|
||||
|
||||
|
||||
@@ -651,31 +651,6 @@ public class AzureQueuePushEngineTests
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PushSyncOrganizationStatusAsync_SendsExpectedResponse()
|
||||
{
|
||||
var organization = new Organization
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Enabled = true,
|
||||
};
|
||||
|
||||
var expectedPayload = new JsonObject
|
||||
{
|
||||
["Type"] = 18,
|
||||
["Payload"] = new JsonObject
|
||||
{
|
||||
["OrganizationId"] = organization.Id,
|
||||
["Enabled"] = organization.Enabled,
|
||||
},
|
||||
};
|
||||
|
||||
await VerifyNotificationAsync(
|
||||
async sut => await sut.PushSyncOrganizationStatusAsync(organization),
|
||||
expectedPayload
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PushSyncOrganizationCollectionManagementSettingsAsync_SendsExpectedResponse()
|
||||
{
|
||||
|
||||
@@ -413,21 +413,6 @@ public abstract class PushTestBase
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PushSyncOrganizationStatusAsync_SendsExpectedResponse()
|
||||
{
|
||||
var organization = new Organization
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Enabled = true,
|
||||
};
|
||||
|
||||
await VerifyNotificationAsync(
|
||||
async sut => await sut.PushSyncOrganizationStatusAsync(organization),
|
||||
GetPushSyncOrganizationStatusResponsePayload(organization)
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PushSyncOrganizationCollectionManagementSettingsAsync_SendsExpectedResponse()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user