1
0
mirror of https://github.com/bitwarden/server synced 2026-01-04 09:33:40 +00:00

Merge branch 'master' into flexible-collections/deprecate-custom-collection-perm

This commit is contained in:
Rui Tome
2023-11-02 14:52:14 +00:00
45 changed files with 1481 additions and 178 deletions

View File

@@ -133,8 +133,8 @@ public class SecretsManagerOrganizationCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
const PlanType planType = PlanType.EnterpriseAnnually;
var organizationId = Guid.NewGuid();
var planType = PlanType.EnterpriseAnnually;
fixture.Customize<Organization>(composer => composer
.With(o => o.Id, organizationId)
@@ -143,8 +143,7 @@ public class SecretsManagerOrganizationCustomization : ICustomization
.With(o => o.PlanType, planType)
.With(o => o.Plan, StaticStore.GetPlan(planType).Name)
.With(o => o.MaxAutoscaleSmSeats, (int?)null)
.With(o => o.MaxAutoscaleSmServiceAccounts, (int?)null)
);
.With(o => o.MaxAutoscaleSmServiceAccounts, (int?)null));
}
}

View File

@@ -15,17 +15,45 @@ public class SecretsManagerSubscriptionUpdateTests
[BitAutoData(PlanType.Custom)]
[BitAutoData(PlanType.FamiliesAnnually)]
[BitAutoData(PlanType.FamiliesAnnually2019)]
[BitAutoData(PlanType.EnterpriseMonthly2019)]
[BitAutoData(PlanType.EnterpriseAnnually2019)]
[BitAutoData(PlanType.TeamsMonthly2019)]
[BitAutoData(PlanType.TeamsAnnually2019)]
public async Task UpdateSubscriptionAsync_WithNonSecretsManagerPlanType_ThrowsBadRequestException(
public Task UpdateSubscriptionAsync_WithNonSecretsManagerPlanType_ThrowsBadRequestException(
PlanType planType,
Organization organization)
{
// Arrange
organization.PlanType = planType;
// Act
var exception = Assert.Throws<NotFoundException>(() => new SecretsManagerSubscriptionUpdate(organization, false));
// Assert
Assert.Contains("Invalid Secrets Manager plan", exception.Message, StringComparison.InvariantCultureIgnoreCase);
return Task.CompletedTask;
}
[Theory]
[BitAutoData(PlanType.EnterpriseMonthly2019)]
[BitAutoData(PlanType.EnterpriseMonthly2020)]
[BitAutoData(PlanType.EnterpriseMonthly)]
[BitAutoData(PlanType.EnterpriseAnnually2019)]
[BitAutoData(PlanType.EnterpriseAnnually2020)]
[BitAutoData(PlanType.EnterpriseAnnually)]
[BitAutoData(PlanType.TeamsMonthly2019)]
[BitAutoData(PlanType.TeamsMonthly2020)]
[BitAutoData(PlanType.TeamsMonthly)]
[BitAutoData(PlanType.TeamsAnnually2019)]
[BitAutoData(PlanType.TeamsAnnually2020)]
[BitAutoData(PlanType.TeamsAnnually)]
public void UpdateSubscription_WithNonSecretsManagerPlanType_DoesNotThrowException(
PlanType planType,
Organization organization)
{
// Arrange
organization.PlanType = planType;
// Act
var ex = Record.Exception(() => new SecretsManagerSubscriptionUpdate(organization, false));
// Assert
Assert.Null(ex);
}
}

View File

@@ -739,4 +739,300 @@ public class StripePaymentServiceTests
Assert.Null(result);
}
[Theory, BitAutoData]
public async Task PreviewUpcomingInvoiceAndPayAsync_WithInAppPaymentMethod_ThrowsBadRequestException(SutProvider<StripePaymentService> sutProvider,
Organization subscriber, List<Stripe.InvoiceSubscriptionItemOptions> subItemOptions)
{
var stripeAdapter = sutProvider.GetDependency<IStripeAdapter>();
stripeAdapter.CustomerGetAsync(Arg.Any<string>(), Arg.Any<Stripe.CustomerGetOptions>())
.Returns(new Stripe.Customer { Metadata = new Dictionary<string, string> { { "appleReceipt", "dummyData" } } });
var ex = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.PreviewUpcomingInvoiceAndPayAsync(subscriber, subItemOptions));
Assert.Equal("Cannot perform this action with in-app purchase payment method. Contact support.", ex.Message);
}
[Theory, BitAutoData]
public async void PreviewUpcomingInvoiceAndPayAsync_UpcomingInvoiceBelowThreshold_DoesNotInvoiceNow(SutProvider<StripePaymentService> sutProvider,
Organization subscriber, List<Stripe.InvoiceSubscriptionItemOptions> subItemOptions)
{
var prorateThreshold = 50000;
var invoiceAmountBelowThreshold = prorateThreshold - 100;
var customer = MockStripeCustomer(subscriber);
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(default, default).ReturnsForAnyArgs(customer);
var invoiceItem = MockInoviceItemList(subscriber, "planId", invoiceAmountBelowThreshold, customer);
sutProvider.GetDependency<IStripeAdapter>().InvoiceItemListAsync(new Stripe.InvoiceItemListOptions
{
Customer = subscriber.GatewayCustomerId
}).ReturnsForAnyArgs(invoiceItem);
var invoiceLineItem = CreateInvoiceLineTime(subscriber, "planId", invoiceAmountBelowThreshold);
sutProvider.GetDependency<IStripeAdapter>().InvoiceUpcomingAsync(new Stripe.UpcomingInvoiceOptions
{
Customer = subscriber.GatewayCustomerId,
Subscription = subscriber.GatewaySubscriptionId,
SubscriptionItems = subItemOptions
}).ReturnsForAnyArgs(invoiceLineItem);
sutProvider.GetDependency<IStripeAdapter>().InvoiceCreateAsync(Arg.Is<Stripe.InvoiceCreateOptions>(options =>
options.CollectionMethod == "send_invoice" &&
options.DaysUntilDue == 1 &&
options.Customer == subscriber.GatewayCustomerId &&
options.Subscription == subscriber.GatewaySubscriptionId &&
options.DefaultPaymentMethod == customer.InvoiceSettings.DefaultPaymentMethod.Id
)).ReturnsForAnyArgs(new Stripe.Invoice
{
Id = "mockInvoiceId",
CollectionMethod = "send_invoice",
DueDate = DateTime.Now.AddDays(1),
Customer = customer,
Subscription = new Stripe.Subscription
{
Id = "mockSubscriptionId",
Customer = customer,
Status = "active",
CurrentPeriodStart = DateTime.UtcNow,
CurrentPeriodEnd = DateTime.UtcNow.AddMonths(1),
CollectionMethod = "charge_automatically",
},
DefaultPaymentMethod = customer.InvoiceSettings.DefaultPaymentMethod,
AmountDue = invoiceAmountBelowThreshold,
Currency = "usd",
Status = "draft",
});
var result = await sutProvider.Sut.PreviewUpcomingInvoiceAndPayAsync(subscriber, new List<Stripe.InvoiceSubscriptionItemOptions>(), prorateThreshold);
Assert.False(result.IsInvoicedNow);
Assert.Null(result.PaymentIntentClientSecret);
}
[Theory, BitAutoData]
public async void PreviewUpcomingInvoiceAndPayAsync_NoPaymentMethod_ThrowsBadRequestException(SutProvider<StripePaymentService> sutProvider,
Organization subscriber, List<Stripe.InvoiceSubscriptionItemOptions> subItemOptions, string planId)
{
var prorateThreshold = 120000;
var invoiceAmountBelowThreshold = prorateThreshold;
var customer = new Stripe.Customer
{
Metadata = new Dictionary<string, string>(),
Id = subscriber.GatewayCustomerId,
DefaultSource = null,
InvoiceSettings = new Stripe.CustomerInvoiceSettings
{
DefaultPaymentMethod = null
}
};
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(default, default).ReturnsForAnyArgs(customer);
var invoiceItem = MockInoviceItemList(subscriber, planId, invoiceAmountBelowThreshold, customer);
sutProvider.GetDependency<IStripeAdapter>().InvoiceItemListAsync(new Stripe.InvoiceItemListOptions
{
Customer = subscriber.GatewayCustomerId
}).ReturnsForAnyArgs(invoiceItem);
var invoiceLineItem = CreateInvoiceLineTime(subscriber, planId, invoiceAmountBelowThreshold);
sutProvider.GetDependency<IStripeAdapter>().InvoiceUpcomingAsync(new Stripe.UpcomingInvoiceOptions
{
Customer = subscriber.GatewayCustomerId,
Subscription = subscriber.GatewaySubscriptionId,
SubscriptionItems = subItemOptions
}).ReturnsForAnyArgs(invoiceLineItem);
var ex = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.PreviewUpcomingInvoiceAndPayAsync(subscriber, subItemOptions));
Assert.Equal("No payment method is available.", ex.Message);
}
[Theory, BitAutoData]
public async void PreviewUpcomingInvoiceAndPayAsync_UpcomingInvoiceAboveThreshold_DoesInvoiceNow(SutProvider<StripePaymentService> sutProvider,
Organization subscriber, List<Stripe.InvoiceSubscriptionItemOptions> subItemOptions, string planId)
{
var prorateThreshold = 50000;
var invoiceAmountBelowThreshold = 100000;
var customer = MockStripeCustomer(subscriber);
sutProvider.GetDependency<IStripeAdapter>().CustomerGetAsync(default, default).ReturnsForAnyArgs(customer);
var invoiceItem = MockInoviceItemList(subscriber, planId, invoiceAmountBelowThreshold, customer);
sutProvider.GetDependency<IStripeAdapter>().InvoiceItemListAsync(new Stripe.InvoiceItemListOptions
{
Customer = subscriber.GatewayCustomerId
}).ReturnsForAnyArgs(invoiceItem);
var invoiceLineItem = CreateInvoiceLineTime(subscriber, planId, invoiceAmountBelowThreshold);
sutProvider.GetDependency<IStripeAdapter>().InvoiceUpcomingAsync(new Stripe.UpcomingInvoiceOptions
{
Customer = subscriber.GatewayCustomerId,
Subscription = subscriber.GatewaySubscriptionId,
SubscriptionItems = subItemOptions
}).ReturnsForAnyArgs(invoiceLineItem);
var invoice = MockInVoice(customer, invoiceAmountBelowThreshold);
sutProvider.GetDependency<IStripeAdapter>().InvoiceCreateAsync(Arg.Is<Stripe.InvoiceCreateOptions>(options =>
options.CollectionMethod == "send_invoice" &&
options.DaysUntilDue == 1 &&
options.Customer == subscriber.GatewayCustomerId &&
options.Subscription == subscriber.GatewaySubscriptionId &&
options.DefaultPaymentMethod == customer.InvoiceSettings.DefaultPaymentMethod.Id
)).ReturnsForAnyArgs(invoice);
var result = await sutProvider.Sut.PreviewUpcomingInvoiceAndPayAsync(subscriber, new List<Stripe.InvoiceSubscriptionItemOptions>(), prorateThreshold);
await sutProvider.GetDependency<IStripeAdapter>().Received(1).InvoicePayAsync(invoice.Id,
Arg.Is<Stripe.InvoicePayOptions>((options =>
options.OffSession == true
)));
Assert.True(result.IsInvoicedNow);
Assert.Null(result.PaymentIntentClientSecret);
}
private static Stripe.Invoice MockInVoice(Stripe.Customer customer, int invoiceAmountBelowThreshold) =>
new()
{
Id = "mockInvoiceId",
CollectionMethod = "send_invoice",
DueDate = DateTime.Now.AddDays(1),
Customer = customer,
Subscription = new Stripe.Subscription
{
Id = "mockSubscriptionId",
Customer = customer,
Status = "active",
CurrentPeriodStart = DateTime.UtcNow,
CurrentPeriodEnd = DateTime.UtcNow.AddMonths(1),
CollectionMethod = "charge_automatically",
},
DefaultPaymentMethod = customer.InvoiceSettings.DefaultPaymentMethod,
AmountDue = invoiceAmountBelowThreshold,
Currency = "usd",
Status = "draft",
};
private static List<Stripe.InvoiceItem> MockInoviceItemList(Organization subscriber, string planId, int invoiceAmountBelowThreshold, Stripe.Customer customer) =>
new()
{
new Stripe.InvoiceItem
{
Id = "ii_1234567890",
Amount = invoiceAmountBelowThreshold,
Currency = "usd",
CustomerId = subscriber.GatewayCustomerId,
Description = "Sample invoice item 1",
Date = DateTime.UtcNow,
Discountable = true,
InvoiceId = "548458365"
},
new Stripe.InvoiceItem
{
Id = "ii_0987654321",
Amount = invoiceAmountBelowThreshold,
Currency = "usd",
CustomerId = customer.Id,
Description = "Sample invoice item 2",
Date = DateTime.UtcNow.AddDays(-5),
Discountable = false,
InvoiceId = null,
Proration = true,
Plan = new Stripe.Plan
{
Id = planId,
Amount = invoiceAmountBelowThreshold,
Currency = "usd",
Interval = "month",
IntervalCount = 1,
},
}
};
private static Stripe.Customer MockStripeCustomer(Organization subscriber)
{
var customer = new Stripe.Customer
{
Metadata = new Dictionary<string, string>(),
Id = subscriber.GatewayCustomerId,
DefaultSource = new Stripe.Card
{
Id = "card_12345",
Last4 = "1234",
Brand = "Visa",
ExpYear = 2025,
ExpMonth = 12
},
InvoiceSettings = new Stripe.CustomerInvoiceSettings
{
DefaultPaymentMethod = new Stripe.PaymentMethod
{
Id = "pm_12345",
Type = "card",
Card = new Stripe.PaymentMethodCard
{
Last4 = "1234",
Brand = "Visa",
ExpYear = 2025,
ExpMonth = 12
}
}
}
};
return customer;
}
private static Stripe.Invoice CreateInvoiceLineTime(Organization subscriber, string planId, int invoiceAmountBelowThreshold) =>
new()
{
AmountDue = invoiceAmountBelowThreshold,
AmountPaid = 0,
AmountRemaining = invoiceAmountBelowThreshold,
CustomerId = subscriber.GatewayCustomerId,
SubscriptionId = subscriber.GatewaySubscriptionId,
ApplicationFeeAmount = 0,
Currency = "usd",
Description = "Upcoming Invoice",
Discount = null,
DueDate = DateTime.UtcNow.AddDays(1),
EndingBalance = 0,
Number = "INV12345",
Paid = false,
PeriodStart = DateTime.UtcNow,
PeriodEnd = DateTime.UtcNow.AddMonths(1),
ReceiptNumber = null,
StartingBalance = 0,
Status = "draft",
Id = "ii_0987654321",
Total = invoiceAmountBelowThreshold,
Lines = new Stripe.StripeList<Stripe.InvoiceLineItem>
{
Data = new List<Stripe.InvoiceLineItem>
{
new Stripe.InvoiceLineItem
{
Amount = invoiceAmountBelowThreshold,
Currency = "usd",
Description = "Sample line item",
Id = "ii_0987654321",
Livemode = false,
Object = "line_item",
Discountable = false,
Period = new Stripe.InvoiceLineItemPeriod()
{
Start = DateTime.UtcNow,
End = DateTime.UtcNow.AddMonths(1)
},
Plan = new Stripe.Plan
{
Id = planId,
Amount = invoiceAmountBelowThreshold,
Currency = "usd",
Interval = "month",
IntervalCount = 1,
},
Proration = true,
Quantity = 1,
Subscription = subscriber.GatewaySubscriptionId,
SubscriptionItem = "si_12345",
Type = "subscription",
UnitAmountExcludingTax = invoiceAmountBelowThreshold,
}
}
}
};
}

View File

@@ -10,10 +10,10 @@ public class StaticStoreTests
[Fact]
public void StaticStore_Initialization_Success()
{
var plans = StaticStore.Plans;
var plans = StaticStore.Plans.ToList();
Assert.NotNull(plans);
Assert.NotEmpty(plans);
Assert.Equal(12, plans.Count());
Assert.Equal(16, plans.Count);
}
[Theory]