diff --git a/EShop.sln b/EShop.sln index 44c76155..9031a10d 100644 --- a/EShop.sln +++ b/EShop.sln @@ -423,6 +423,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Products.Plug EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EasyAbp.EShop.Products.Plugins.FlashSales.HttpApi.Client", "plugins\FlashSales\src\EasyAbp.EShop.Products.Plugins.FlashSales.HttpApi.Client\EasyAbp.EShop.Products.Plugins.FlashSales.HttpApi.Client.csproj", "{274769DC-5DD6-4CFD-8078-5E0E0CE8D6D8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests", "plugins\FlashSales\test\EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests\EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests.csproj", "{17A3486C-1845-4B4E-B1A6-752106F0C309}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1101,6 +1103,10 @@ Global {274769DC-5DD6-4CFD-8078-5E0E0CE8D6D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {274769DC-5DD6-4CFD-8078-5E0E0CE8D6D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {274769DC-5DD6-4CFD-8078-5E0E0CE8D6D8}.Release|Any CPU.Build.0 = Release|Any CPU + {17A3486C-1845-4B4E-B1A6-752106F0C309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17A3486C-1845-4B4E-B1A6-752106F0C309}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17A3486C-1845-4B4E-B1A6-752106F0C309}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17A3486C-1845-4B4E-B1A6-752106F0C309}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1312,6 +1318,7 @@ Global {F08D9409-4D01-4639-A7B8-A70B7ED8E0F9} = {F29C5BCD-E6C0-4556-A631-CACA41B1050B} {B137BF4B-8C0A-4CE2-AF22-BD9BD29C86B7} = {F29C5BCD-E6C0-4556-A631-CACA41B1050B} {274769DC-5DD6-4CFD-8078-5E0E0CE8D6D8} = {F29C5BCD-E6C0-4556-A631-CACA41B1050B} + {17A3486C-1845-4B4E-B1A6-752106F0C309} = {9C180C9E-50E9-4624-BE06-5C8C24A028E4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests.abppkg.json b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests.abppkg.json new file mode 100644 index 00000000..a686451f --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests.abppkg.json @@ -0,0 +1,3 @@ +{ + "role": "lib.test" +} \ No newline at end of file diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests.csproj b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests.csproj new file mode 100644 index 00000000..bd18bfdc --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + + + + + + + + + + diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Orders/Orders/CreateFlashSaleOrderEventHandlerTests.cs b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Orders/Orders/CreateFlashSaleOrderEventHandlerTests.cs new file mode 100644 index 00000000..b7643685 --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Orders/Orders/CreateFlashSaleOrderEventHandlerTests.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using EasyAbp.EShop.Plugins.FlashSales; +using EasyAbp.EShop.Products.ProductDetails.Dtos; +using EasyAbp.EShop.Products.ProductDetails; +using EasyAbp.EShop.Products.Products; +using EasyAbp.EShop.Products.Products.Dtos; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using NSubstitute; +using Xunit; +using EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; +using Volo.Abp.Users; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.MultiTenancy; +using EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults; + +namespace EasyAbp.EShop.Orders.Orders; + +public class CreateFlashSaleOrderEventHandlerTests : OrdersPluginsFlashSalesApplicationTestBase +{ + protected CreateFlashSaleOrderEventHandler EventHandler { get; } + + protected ICurrentUser CurrentUser { get; } + + protected ICurrentTenant CurrentTenant { get; } + + protected IDistributedEventBus DistributedEventBus { get; } + + protected IFlashSalePlanHasher FlashSalePlanHasher { get; } + + protected IOrderRepository OrderRepository { get; } + + protected ProductDto Product1 { get; set; } + + public CreateFlashSaleOrderEventHandlerTests() + { + EventHandler = GetRequiredService(); + CurrentUser = GetRequiredService(); + CurrentTenant = GetRequiredService(); + DistributedEventBus = GetRequiredService(); + FlashSalePlanHasher = GetRequiredService(); + OrderRepository = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + Product1 = CreateMockProductDto(); + + var productAppService = Substitute.For(); + productAppService.GetAsync(FlashSalesTestData.Product1Id).Returns(Task.FromResult(Product1)); + services.Replace(ServiceDescriptor.Singleton(productAppService)); + + var productDetailAppService = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(productDetailAppService)); + productDetailAppService.GetAsync(FlashSalesTestData.ProductDetail1Id).Returns(Task.FromResult( + new ProductDetailDto + { + Id = FlashSalesTestData.ProductDetail1Id, + CreationTime = FlashSalesTestData.ProductDetailLastModificationTime, + LastModificationTime = FlashSalesTestData.ProductDetailLastModificationTime, + StoreId = FlashSalesTestData.Store1Id, + Description = "My Details 1" + })); + productDetailAppService.GetAsync(FlashSalesTestData.ProductDetail2Id).Returns(Task.FromResult( + new ProductDetailDto + { + Id = FlashSalesTestData.ProductDetail2Id, + StoreId = FlashSalesTestData.Store1Id, + Description = "My Details 2" + })); + + var distributedEventBus = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(distributedEventBus)); + + var flashSalePlanHasher = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(flashSalePlanHasher)); + + var orderRepository = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(orderRepository)); + + base.AfterAddApplication(services); + } + + [Fact] + public async Task HandleEventAsync() + { + FlashSalePlanHasher.HashAsync(default, default, default) + .ReturnsForAnyArgs("My Hash Token"); + OrderRepository.InsertAsync(default, default, default) + .ReturnsForAnyArgs(callInfo => callInfo.Arg()); + + var createFlashSaleOrderEto = new CreateFlashSaleOrderEto() + { + TenantId = CurrentTenant.Id, + PlanId = FlashSalesTestData.Plan1Id, + StoreId = FlashSalesTestData.Store1Id, + UserId = CurrentUser.GetId(), + PendingResultId = FlashSalesTestData.Result1Id, + CreateTime = DateTime.Now, + CustomerRemark = "My Remark", + HashToken = "My Hash Token", + Plan = new FlashSalePlanEto + { + Id = FlashSalesTestData.Plan1Id, + TenantId = CurrentTenant.Id, + StoreId = FlashSalesTestData.Store1Id, + BeginTime = DateTime.Now, + EndTime = DateTime.Now.AddMinutes(30), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = true + } + }; + + await EventHandler.HandleEventAsync(createFlashSaleOrderEto); + + await DistributedEventBus.Received() + .PublishAsync(Arg.Is(eto => + eto.TenantId == CurrentTenant.Id && + eto.PendingResultId == FlashSalesTestData.Result1Id && + eto.Success && + eto.StoreId == FlashSalesTestData.Store1Id && + eto.PlanId == FlashSalesTestData.Plan1Id && + eto.UserId == CurrentUser.GetId() && + eto.OrderId != null && + eto.Reason == null + )); + } + + [Fact] + public async Task HandleEventAsync_Should_Publish_False_When_ValidateHashToken_Failed() + { + FlashSalePlanHasher.HashAsync(default, default, default) + .ReturnsForAnyArgs("My Hash Token"); + + var createFlashSaleOrderEto = new CreateFlashSaleOrderEto() + { + TenantId = CurrentTenant.Id, + PlanId = FlashSalesTestData.Plan1Id, + StoreId = FlashSalesTestData.Store1Id, + UserId = CurrentUser.GetId(), + PendingResultId = FlashSalesTestData.Result1Id, + CreateTime = DateTime.Now, + CustomerRemark = "My Remark", + HashToken = "My Hash Token Failed", + Plan = new FlashSalePlanEto + { + Id = FlashSalesTestData.Plan1Id, + TenantId = CurrentTenant.Id, + StoreId = FlashSalesTestData.Store1Id, + BeginTime = DateTime.Now, + EndTime = DateTime.Now.AddMinutes(30), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = true + } + }; + + await EventHandler.HandleEventAsync(createFlashSaleOrderEto); + + await DistributedEventBus.Received() + .PublishAsync(Arg.Is(eto => + eto.TenantId == CurrentTenant.Id && + eto.PendingResultId == FlashSalesTestData.Result1Id && + !eto.Success && + eto.StoreId == FlashSalesTestData.Store1Id && + eto.PlanId == FlashSalesTestData.Plan1Id && + eto.UserId == CurrentUser.GetId() && + eto.OrderId == null && + eto.Reason == FlashSaleResultFailedReason.InvalidHashToken + )); + } +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Orders/Plugins/FlashSales/EShopOrdersPluginsFlashSalesApplicationTestsModule.cs b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Orders/Plugins/FlashSales/EShopOrdersPluginsFlashSalesApplicationTestsModule.cs new file mode 100644 index 00000000..3ac63e8e --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Orders/Plugins/FlashSales/EShopOrdersPluginsFlashSalesApplicationTestsModule.cs @@ -0,0 +1,13 @@ +using EasyAbp.EShop.Orders.Plugins.FlashSales; +using Volo.Abp.Modularity; + +namespace EasyAbp.EShop.Plugins.FlashSales; + +[DependsOn( + typeof(EShopOrdersPluginsFlashSalesApplicationModule), + typeof(EShopPluginsFlashSalesTestBaseModule) + )] +public class EShopOrdersPluginsFlashSalesApplicationTestsModule : AbpModule +{ + +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Orders/Plugins/FlashSales/OrdersPluginsFlashSalesApplicationTestBase.cs b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Orders/Plugins/FlashSales/OrdersPluginsFlashSalesApplicationTestBase.cs new file mode 100644 index 00000000..5abed316 --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Orders/Plugins/FlashSales/OrdersPluginsFlashSalesApplicationTestBase.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using EasyAbp.EShop.Products.Products; +using EasyAbp.EShop.Products.Products.Dtos; + +namespace EasyAbp.EShop.Plugins.FlashSales; + +/* Inherit from this class for your application layer tests. + * See SampleAppService_Tests for example. + */ +public abstract class OrdersPluginsFlashSalesApplicationTestBase : FlashSalesTestBase +{ + protected virtual ProductDto CreateMockProductDto() + { + return new ProductDto + { + CreationTime = DateTime.Now, + IsPublished = true, + Id = FlashSalesTestData.Product1Id, + StoreId = FlashSalesTestData.Store1Id, + ProductGroupName = "Default", + ProductGroupDisplayName = "Default", + UniqueName = "Pencil", + DisplayName = "Hello pencil", + ProductDetailId = FlashSalesTestData.ProductDetail1Id, + ProductSkus = new List + { + new ProductSkuDto + { + Id = FlashSalesTestData.ProductSku1Id, + Name = "My SKU", + OrderMinQuantity = 0, + OrderMaxQuantity = 100, + AttributeOptionIds = new List(), + Price = 1m, + Currency = "USD", + ProductDetailId = null, + Inventory = 10, + }, + new ProductSkuDto + { + Id = FlashSalesTestData.ProductSku2Id, + Name = "My SKU 2", + OrderMinQuantity = 0, + OrderMaxQuantity = 100, + AttributeOptionIds = new List(), + Price = 2m, + Currency = "USD", + ProductDetailId = FlashSalesTestData.ProductDetail2Id, + Inventory = 0 + }, + new ProductSkuDto + { + Id = FlashSalesTestData.ProductSku3Id, + Name = "My SKU 3", + OrderMinQuantity = 0, + OrderMaxQuantity = 100, + AttributeOptionIds = new List(), + Price = 3m, + Currency = "USD", + ProductDetailId = FlashSalesTestData.ProductDetail2Id, + Inventory = 1 + } + }, + InventoryStrategy = InventoryStrategy.FlashSales, + LastModificationTime = FlashSalesTestData.ProductLastModificationTime + }; + } +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/FodyWeavers.xml b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/FodyWeavers.xml new file mode 100644 index 00000000..1715698c --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/FodyWeavers.xsd b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/FodyWeavers.xsd new file mode 100644 index 00000000..ffa6fc4b --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Orders.Plugins.FlashSales.Application.Tests/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp.EShop.Plugins.FlashSales.Application.Tests.csproj b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp.EShop.Plugins.FlashSales.Application.Tests.csproj index d9dbd3e1..0719f417 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp.EShop.Plugins.FlashSales.Application.Tests.csproj +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp.EShop.Plugins.FlashSales.Application.Tests.csproj @@ -1,4 +1,4 @@ - + net6.0 diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/CreateTimeRange.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/CreateTimeRange.cs new file mode 100644 index 00000000..2dbc3aa4 --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/CreateTimeRange.cs @@ -0,0 +1,9 @@ +namespace EasyAbp.EShop.Plugins.FlashSales; + +public enum CreateTimeRange +{ + Starting, + NotStart, + Expired, + WillBeExpired, +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationTestModule.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesApplicationTestModule.cs similarity index 56% rename from plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationTestModule.cs rename to plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesApplicationTestModule.cs index 3a60972a..cf845dff 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationTestModule.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesApplicationTestModule.cs @@ -4,9 +4,9 @@ namespace EasyAbp.EShop.Plugins.FlashSales; [DependsOn( typeof(EShopPluginsFlashSalesApplicationModule), - typeof(FlashSalesDomainTestModule) + typeof(EShopPluginsFlashSalesDomainTestModule) )] -public class FlashSalesApplicationTestModule : AbpModule +public class EShopPluginsFlashSalesApplicationTestModule : AbpModule { } diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppServiceTests.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppServiceTests.cs new file mode 100644 index 00000000..879eb260 --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppServiceTests.cs @@ -0,0 +1,483 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using EasyAbp.Eshop.Products.Products; +using EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans.Dtos; +using EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults; +using EasyAbp.EShop.Products.Products; +using EasyAbp.EShop.Products.Products.Dtos; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; +using NSubstitute; +using Shouldly; +using Volo.Abp; +using Volo.Abp.Caching; +using Volo.Abp.DistributedLocking; +using Volo.Abp.Domain.Entities; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Users; +using Xunit; + +namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; +public class FlashSalePlanAppServiceTests : FlashSalesApplicationTestBase +{ + protected IFlashSalePlanAppService AppService { get; } + + protected IDistributedEventBus DistributedEventBus { get; } + + private ProductDto Product1 { get; set; } + + public FlashSalePlanAppServiceTests() + { + AppService = GetRequiredService(); + DistributedEventBus = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + Product1 = CreateMockProductDto(); + + var productAppService = Substitute.For(); + productAppService.GetAsync(FlashSalesTestData.Product1Id).Returns(Task.FromResult(Product1)); + services.Replace(ServiceDescriptor.Singleton(productAppService)); + + services.Replace(ServiceDescriptor.Transient()); + + var distributedEventBus = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(distributedEventBus)); + base.AfterAddApplication(services); + } + + [Fact] + public async Task GetAsync() + { + var returnFlashSalePlan = await CreateFlashSalePlanAsync(); + + var flashSalePlan = await AppService.GetAsync(returnFlashSalePlan.Id); + + flashSalePlan.ShouldNotBeNull(); + flashSalePlan.Id.ShouldBe(returnFlashSalePlan.Id); + flashSalePlan.StoreId.ShouldBe(returnFlashSalePlan.StoreId); + flashSalePlan.BeginTime.ShouldBe(returnFlashSalePlan.BeginTime); + flashSalePlan.EndTime.ShouldBe(returnFlashSalePlan.EndTime); + flashSalePlan.ProductId.ShouldBe(returnFlashSalePlan.ProductId); + flashSalePlan.ProductSkuId.ShouldBe(returnFlashSalePlan.ProductSkuId); + flashSalePlan.IsPublished.ShouldBe(returnFlashSalePlan.IsPublished); + + returnFlashSalePlan = await CreateFlashSalePlanAsync(isPublished: false); + + flashSalePlan = await AppService.GetAsync(returnFlashSalePlan.Id); + + flashSalePlan.ShouldNotBeNull(); + flashSalePlan.Id.ShouldBe(returnFlashSalePlan.Id); + flashSalePlan.StoreId.ShouldBe(returnFlashSalePlan.StoreId); + flashSalePlan.BeginTime.ShouldBe(returnFlashSalePlan.BeginTime); + flashSalePlan.EndTime.ShouldBe(returnFlashSalePlan.EndTime); + flashSalePlan.ProductId.ShouldBe(returnFlashSalePlan.ProductId); + flashSalePlan.ProductSkuId.ShouldBe(returnFlashSalePlan.ProductSkuId); + flashSalePlan.IsPublished.ShouldBe(returnFlashSalePlan.IsPublished); + } + + [Fact] + public async Task GetListAsync() + { + var publishedPlan = await CreateFlashSalePlanAsync(isPublished: true); + var unpublishedPlan = await CreateFlashSalePlanAsync(isPublished: false); + + var allListDto = await AppService.GetListAsync(new FlashSalePlanGetListInput() + { + IncludeUnpublished = true + }); + + allListDto.TotalCount.ShouldBeGreaterThan(0); + allListDto.Items.FirstOrDefault(x => x.Id == publishedPlan.Id) + .ShouldNotBeNull() + .Id.ShouldBe(publishedPlan.Id); + + allListDto.Items.FirstOrDefault(x => x.Id == unpublishedPlan.Id) + .ShouldNotBeNull() + .Id.ShouldBe(unpublishedPlan.Id); + + var publishedListDto = await AppService.GetListAsync(new FlashSalePlanGetListInput()); + + publishedListDto.TotalCount.ShouldBeGreaterThan(0); + publishedListDto.Items.FirstOrDefault(x => x.Id == publishedPlan.Id) + .ShouldNotBeNull() + .Id.ShouldBe(publishedPlan.Id); + + publishedListDto.Items.FirstOrDefault(x => x.Id == unpublishedPlan.Id) + .ShouldBeNull(); + } + + [Fact] + public async Task CreateAsync() + { + var createDto = new FlashSalePlanCreateDto() + { + StoreId = FlashSalesTestData.Store1Id, + BeginTime = DateTime.Now, + EndTime = DateTime.Now.AddMinutes(30), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = true + }; + var returnFlashSalePlanDto = await AppService.CreateAsync(createDto); + + var flashSalePlan = await AppService.GetAsync(returnFlashSalePlanDto.Id); + + flashSalePlan.Id.ShouldBe(returnFlashSalePlanDto.Id); + flashSalePlan.StoreId.ShouldBe(createDto.StoreId); + flashSalePlan.BeginTime.ShouldBe(createDto.BeginTime); + flashSalePlan.EndTime.ShouldBe(createDto.EndTime); + flashSalePlan.ProductId.ShouldBe(createDto.ProductId); + flashSalePlan.ProductSkuId.ShouldBe(createDto.ProductSkuId); + flashSalePlan.IsPublished.ShouldBe(createDto.IsPublished); + + return flashSalePlan; + } + + [Fact] + public async Task CreateAsync_Should_Throw_Expcetion_When_Validate_Product_Failed() + { + var createDto = new FlashSalePlanCreateDto() + { + StoreId = FlashSalesTestData.Store1Id, + BeginTime = DateTime.Now, + EndTime = DateTime.Now.AddMinutes(30), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = true + }; + + Product1.StoreId = Guid.NewGuid(); + await AppService.CreateAsync(createDto).ShouldThrowAsync(); + Product1.StoreId = FlashSalesTestData.Store1Id; + + Product1.InventoryStrategy = InventoryStrategy.ReduceAfterPlacing; + await AppService.CreateAsync(createDto).ShouldThrowAsync(); + + Product1.StoreId = FlashSalesTestData.Store1Id; + Product1.InventoryStrategy = InventoryStrategy.FlashSales; + } + + [Fact] + public async Task UpdateAsync() + { + var createDto = new FlashSalePlanCreateDto() + { + StoreId = FlashSalesTestData.Store1Id, + BeginTime = DateTime.Now, + EndTime = DateTime.Now.AddMinutes(30), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = true + }; + var returnFlashSalePlanDto = await AppService.CreateAsync(createDto); + var updateDto = new FlashSalePlanUpdateDto() + { + BeginTime = DateTime.Now.AddMinutes(30), + EndTime = DateTime.Now.AddMinutes(60), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = false + }; + + var flashSalePlan = await AppService.UpdateAsync(returnFlashSalePlanDto.Id, updateDto); + + flashSalePlan.Id.ShouldBe(returnFlashSalePlanDto.Id); + flashSalePlan.StoreId.ShouldBe(createDto.StoreId); + flashSalePlan.BeginTime.ShouldBe(updateDto.BeginTime); + flashSalePlan.EndTime.ShouldBe(updateDto.EndTime); + flashSalePlan.ProductId.ShouldBe(updateDto.ProductId); + flashSalePlan.ProductSkuId.ShouldBe(updateDto.ProductSkuId); + flashSalePlan.IsPublished.ShouldBe(updateDto.IsPublished); + } + + [Fact] + public async Task UpdateAsync_Should_Throw_Expcetion_When_Validate_Product_Failed() + { + var createDto = new FlashSalePlanCreateDto() + { + StoreId = FlashSalesTestData.Store1Id, + BeginTime = DateTime.Now, + EndTime = DateTime.Now.AddMinutes(30), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = true + }; + var returnFlashSalePlanDto = await AppService.CreateAsync(createDto); + var updateDto = new FlashSalePlanUpdateDto() + { + BeginTime = DateTime.Now.AddMinutes(30), + EndTime = DateTime.Now.AddMinutes(60), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = false + }; + + Product1.StoreId = Guid.NewGuid(); + await AppService.UpdateAsync(returnFlashSalePlanDto.Id, updateDto).ShouldThrowAsync(); + Product1.StoreId = FlashSalesTestData.Store1Id; + + Product1.InventoryStrategy = InventoryStrategy.ReduceAfterPlacing; + await AppService.UpdateAsync(returnFlashSalePlanDto.Id, updateDto).ShouldThrowAsync(); + + Product1.StoreId = FlashSalesTestData.Store1Id; + Product1.InventoryStrategy = InventoryStrategy.FlashSales; + } + + [Fact] + public async Task UpdateAsync_Should_Throw_Expcetion_When_Has_Result_And_Change_Product() + { + var createDto = new FlashSalePlanCreateDto() + { + StoreId = FlashSalesTestData.Store1Id, + BeginTime = DateTime.Now, + EndTime = DateTime.Now.AddMinutes(30), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = true + }; + var returnFlashSalePlanDto = await AppService.CreateAsync(createDto); + var updateDto = new FlashSalePlanUpdateDto() + { + BeginTime = DateTime.Now.AddMinutes(30), + EndTime = DateTime.Now.AddMinutes(value: 60), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku2Id, + IsPublished = false + }; + await CreatePendingResultAsync(returnFlashSalePlanDto.Id, returnFlashSalePlanDto.StoreId, Guid.NewGuid()); + + await AppService.UpdateAsync(returnFlashSalePlanDto.Id, updateDto).ShouldThrowAsync(); + } + + [Fact] + public async Task DeleteAsync() + { + var createDto = new FlashSalePlanCreateDto() + { + StoreId = FlashSalesTestData.Store1Id, + BeginTime = DateTime.Now, + EndTime = DateTime.Now.AddMinutes(30), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = true + }; + var returnFlashSalePlanDto = await AppService.CreateAsync(createDto); + + await AppService.DeleteAsync(returnFlashSalePlanDto.Id); + await AppService.GetAsync(returnFlashSalePlanDto.Id).ShouldThrowAsync(); + } + + [Fact] + public async Task DeleteAsync_Should_Throw_Expcetion_When_Has_Result() + { + var createDto = new FlashSalePlanCreateDto() + { + StoreId = FlashSalesTestData.Store1Id, + BeginTime = DateTime.Now, + EndTime = DateTime.Now.AddMinutes(30), + ProductId = FlashSalesTestData.Product1Id, + ProductSkuId = FlashSalesTestData.ProductSku1Id, + IsPublished = true + }; + var returnFlashSalePlanDto = await AppService.CreateAsync(createDto); + await CreatePendingResultAsync(returnFlashSalePlanDto.Id, returnFlashSalePlanDto.StoreId, Guid.NewGuid()); + + await AppService.DeleteAsync(returnFlashSalePlanDto.Id).ShouldThrowAsync(); + } + + [Fact] + public async Task PreOrderAsync() + { + var options = GetRequiredService>().Value; + var distributedCache = GetRequiredService>(); + var plan = await CreateFlashSalePlanAsync(); + var preOrderCacheKey = string.Format(FlashSalePlanAppService.PreOrderCacheKeyFormat, plan.Id, CurrentUser.Id); + var hashToken = await GetRequiredService() + .HashAsync(plan.LastModificationTime, Product1.LastModificationTime, Product1.GetSkuById(plan.ProductSkuId).LastModificationTime); + + var dto = await AppService.PreOrderAsync(plan.Id); + + dto.ExpiresInSeconds.ShouldBe(options.PreOrderExpires.TotalSeconds); + var preOrderCacheItem = await distributedCache.GetAsync(preOrderCacheKey); + preOrderCacheItem.ShouldNotBeNull(); + preOrderCacheItem.PlanId.ShouldBe(plan.Id); + preOrderCacheItem.TenantId.ShouldBe(plan.TenantId); + preOrderCacheItem.HashToken.ShouldBe(hashToken); + preOrderCacheItem.ProductId.ShouldBe(plan.ProductId); + preOrderCacheItem.ProductSkuId.ShouldBe(plan.ProductSkuId); + preOrderCacheItem.InventoryProviderName = Product1.InventoryProviderName; + } + + [Fact] + public async Task PreOrderAsync_Should_Throw_Exception_When_Validate_PreOrder_Failed() + { + var plan = await CreateFlashSalePlanAsync(); + + Product1.IsPublished = false; + + (await AppService.PreOrderAsync(plan.Id) + .ShouldThrowAsync()) + .Code.ShouldBe(FlashSalesErrorCodes.ProductIsNotPublished); + + Product1.IsPublished = true; + + Product1.InventoryStrategy = InventoryStrategy.ReduceAfterPlacing; + + await AppService.PreOrderAsync(plan.Id) + .ShouldThrowAsync(); + + Product1.InventoryStrategy = InventoryStrategy.FlashSales; + + var plan2 = await CreateFlashSalePlanAsync(isPublished: false); + await AppService.PreOrderAsync(plan2.Id) + .ShouldThrowAsync(); + + var plan3 = await CreateFlashSalePlanAsync(timeRange: CreateTimeRange.Expired); + (await AppService.PreOrderAsync(plan3.Id) + .ShouldThrowAsync()) + .Code.ShouldBe(FlashSalesErrorCodes.FlashSaleIsOver); + + var plan4 = await CreateFlashSalePlanAsync(useSku2: true); + (await AppService.PreOrderAsync(plan4.Id) + .ShouldThrowAsync()) + .Code.ShouldBe(FlashSalesErrorCodes.ProductSkuInventoryExceeded); + } + + [Fact] + public async Task OrderAsync() + { + var plan = await CreateFlashSalePlanAsync(); + var hashToken = await GetRequiredService() + .HashAsync(plan.LastModificationTime, Product1.LastModificationTime, Product1.GetSkuById(plan.ProductSkuId).LastModificationTime); + var createOrderInput = new CreateOrderInput() + { + CustomerRemark = "remark1", + ExtraProperties = { { "key1", "value1" } } + }; + await AppService.PreOrderAsync(plan.Id); + + var isSucess = await AppService.OrderAsync(plan.Id, createOrderInput); + + isSucess.ShouldBe(true); + await DistributedEventBus.Received().PublishAsync(Arg.Is(eto => + eto.TenantId == plan.TenantId && + eto.StoreId == plan.StoreId && + eto.PlanId == plan.Id && + eto.UserId == CurrentUser.GetId() && + eto.HashToken == hashToken && + eto.CustomerRemark == createOrderInput.CustomerRemark && + eto.Plan != null && + eto.Plan.TenantId == plan.TenantId && + eto.Plan.StoreId == plan.StoreId && + eto.Plan.BeginTime == plan.BeginTime && + eto.Plan.EndTime == plan.EndTime && + eto.Plan.ProductId == plan.ProductId && + eto.Plan.ProductSkuId == plan.ProductSkuId && + eto.Plan.IsPublished == plan.IsPublished && + eto.ExtraProperties.ContainsKey("key1") && + eto.ExtraProperties["key1"].ToString() == "value1" + )); + } + + [Fact] + public async Task OrderAsync_Throw_Exception_When_Not_PreOrder() + { + var plan = await CreateFlashSalePlanAsync(); + var createOrderInput = new CreateOrderInput(); + + (await AppService.OrderAsync(plan.Id, createOrderInput) + .ShouldThrowAsync()) + .Code.ShouldBe(FlashSalesErrorCodes.PreOrderExpired); + } + + [Fact] + public async Task OrderAsync_Throw_Exception_When_FlashSaleNotStarted() + { + var plan = await CreateFlashSalePlanAsync(timeRange: CreateTimeRange.NotStart); + var createOrderInput = new CreateOrderInput(); + await AppService.PreOrderAsync(plan.Id); + + (await AppService.OrderAsync(plan.Id, createOrderInput) + .ShouldThrowAsync()) + .Code.ShouldBe(FlashSalesErrorCodes.FlashSaleNotStarted); + } + + [Fact] + public async Task OrderAsync_Throw_Exception_When_FlashSaleIsOver() + { + var plan = await CreateFlashSalePlanAsync(timeRange: CreateTimeRange.WillBeExpired); + var createOrderInput = new CreateOrderInput(); + await AppService.PreOrderAsync(plan.Id); + + await Task.Delay(TimeSpan.FromSeconds(1.2)); + + (await AppService.OrderAsync(plan.Id, createOrderInput) + .ShouldThrowAsync()) + .Code.ShouldBe(FlashSalesErrorCodes.FlashSaleIsOver); + } + + [Fact] + public async Task OrderAsync_Throw_Exception_When_BusyToCreateFlashSaleOrder() + { + var plan = await CreateFlashSalePlanAsync(); + var createOrderInput = new CreateOrderInput(); + await AppService.PreOrderAsync(plan.Id); + var distributedLock = GetRequiredService(); + var lockKey = $"create-flash-sale-order-{plan.Id}-{CurrentUser.GetId()}"; + + await using var handle = await distributedLock.TryAcquireAsync(lockKey); + + (await AppService.OrderAsync(plan.Id, createOrderInput) + .ShouldThrowAsync()) + .Code.ShouldBe(FlashSalesErrorCodes.BusyToCreateFlashSaleOrder); + } + + [Fact] + public async Task OrderAsync_Throw_Exception_When_Exist_UserFlashSaleResultCache() + { + var plan = await CreateFlashSalePlanAsync(); + var createOrderInput = new CreateOrderInput(); + await AppService.PreOrderAsync(plan.Id); + var distributedCache = GetRequiredService(); + var userId = CurrentUser.GetId(); + var userFlashSaleResultCacheKey = string.Format(FlashSalePlanAppService.UserFlashSaleResultCacheKeyFormat, plan.TenantId, plan.Id, userId); + await distributedCache.SetStringAsync(userFlashSaleResultCacheKey, Guid.NewGuid().ToString()); + + (await AppService.OrderAsync(plan.Id, createOrderInput) + .ShouldThrowAsync()) + .Code.ShouldBe(FlashSalesErrorCodes.DuplicateFlashSalesOrder); + } + + [Fact] + public async Task OrderAsync_Return_False_When_TryReduceInventory_Failed() + { + var plan = await CreateFlashSalePlanAsync(); + var createOrderInput = new CreateOrderInput(); + await AppService.PreOrderAsync(plan.Id); + + FakeFlashSaleInventoryManager.ShouldReduceSuccess = false; + + (await AppService.OrderAsync(plan.Id, createOrderInput)).ShouldBe(false); + } + + [Fact] + public async Task OrderAsync_Return_False_When_Exist_Not_Failed_Result() + { + var plan = await CreateFlashSalePlanAsync(); + var createOrderInput = new CreateOrderInput(); + await AppService.PreOrderAsync(plan.Id); + var userId = GetRequiredService().GetId(); + + await CreatePendingResultAsync(plan.Id, plan.StoreId, userId); + + (await AppService.OrderAsync(plan.Id, createOrderInput) + .ShouldThrowAsync()) + .Code.ShouldBe(FlashSalesErrorCodes.DuplicateFlashSalesOrder); + } +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/RollBackInventoryCreateFlashSaleOrderCompleteEventHandlerTest.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/RollBackInventoryCreateFlashSaleOrderCompleteEventHandlerTest.cs new file mode 100644 index 00000000..164faa82 --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/RollBackInventoryCreateFlashSaleOrderCompleteEventHandlerTest.cs @@ -0,0 +1,171 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using EasyAbp.Eshop.Products.Products; +using EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults; +using EasyAbp.EShop.Products.Products; +using EasyAbp.EShop.Products.Products.Dtos; +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using NSubstitute; +using NSubstitute.ReceivedExtensions; +using Shouldly; +using Volo.Abp; +using Volo.Abp.Caching; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.Users; +using Xunit; + +namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; + +public class RollBackInventoryCreateFlashSaleOrderCompleteEventHandlerTest : FlashSalesApplicationTestBase +{ + protected RollBackInventoryCreateFlashSaleOrderCompleteEventHandler EventHandler { get; } + + protected IDistributedCache DistributedCache { get; } + + protected IFlashSaleInventoryManager FlashSaleInventoryManager { get; set; } + + private ProductDto Product1 { get; set; } + + public RollBackInventoryCreateFlashSaleOrderCompleteEventHandlerTest() + { + EventHandler = GetRequiredService(); + DistributedCache = GetRequiredService(); + FlashSaleInventoryManager = GetRequiredService(); + } + + protected override void AfterAddApplication(IServiceCollection services) + { + Product1 = CreateMockProductDto(); + + var productAppService = Substitute.For(); + productAppService.GetAsync(FlashSalesTestData.Product1Id).Returns(Task.FromResult(Product1)); + services.Replace(ServiceDescriptor.Singleton(productAppService)); + + FlashSaleInventoryManager = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(FlashSaleInventoryManager)); + base.AfterAddApplication(services); + } + + [Fact] + public async Task HandleEventAsync() + { + var plan = await CreateFlashSalePlanAsync(); + var pendingFlashResult = await CreatePendingResultAsync(plan.Id, plan.StoreId, CurrentUser.GetId()); + var userFlashSaleResultCacheKey = string.Format(FlashSalePlanAppService.UserFlashSaleResultCacheKeyFormat, plan.TenantId, plan.Id, CurrentUser.GetId()); + await DistributedCache.SetStringAsync(userFlashSaleResultCacheKey, pendingFlashResult.Id.ToString()); + var createFlashSaleOrderCompleteEto = new CreateFlashSaleOrderCompleteEto() + { + TenantId = pendingFlashResult.TenantId, + PendingResultId = pendingFlashResult.Id, + Success = false, + StoreId = pendingFlashResult.StoreId, + PlanId = pendingFlashResult.PlanId, + OrderId = null, + Reason = FlashSaleResultFailedReason.InvalidHashToken, + UserId = pendingFlashResult.UserId + }; + FlashSaleInventoryManager + .TryRollBackInventoryAsync(plan.TenantId, Product1.InventoryProviderName, plan.StoreId, plan.ProductId, plan.ProductSkuId, 1, true) + .Returns(Task.FromResult(true)); + + await EventHandler.HandleEventAsync(createFlashSaleOrderCompleteEto); + + var userFlashSaleResultCache = await DistributedCache.GetStringAsync(userFlashSaleResultCacheKey); + userFlashSaleResultCache.ShouldBeNull(); + + await FlashSaleInventoryManager.Received() + .TryRollBackInventoryAsync(plan.TenantId, Product1.InventoryProviderName, plan.StoreId, plan.ProductId, plan.ProductSkuId, 1, true); + } + + [Fact] + public async Task HandleEventAsync_Should_Not_Remove_UserFlashSaleResultCache_When_TryRollBackInventory_Failed() + { + var plan = await CreateFlashSalePlanAsync(); + var pendingFlashResult = await CreatePendingResultAsync(plan.Id, plan.StoreId, CurrentUser.GetId()); + var userFlashSaleResultCacheKey = string.Format(FlashSalePlanAppService.UserFlashSaleResultCacheKeyFormat, plan.TenantId, plan.Id, CurrentUser.GetId()); + await DistributedCache.SetStringAsync(userFlashSaleResultCacheKey, pendingFlashResult.Id.ToString()); + var createFlashSaleOrderCompleteEto = new CreateFlashSaleOrderCompleteEto() + { + TenantId = pendingFlashResult.TenantId, + PendingResultId = pendingFlashResult.Id, + Success = false, + StoreId = pendingFlashResult.StoreId, + PlanId = pendingFlashResult.PlanId, + OrderId = null, + Reason = FlashSaleResultFailedReason.InvalidHashToken, + UserId = pendingFlashResult.UserId + }; + FlashSaleInventoryManager + .TryRollBackInventoryAsync(plan.TenantId, Product1.InventoryProviderName, plan.StoreId, plan.ProductId, plan.ProductSkuId, 1, true) + .Returns(Task.FromResult(false)); + + await EventHandler.HandleEventAsync(createFlashSaleOrderCompleteEto); + + var userFlashSaleResultCache = await DistributedCache.GetStringAsync(userFlashSaleResultCacheKey); + userFlashSaleResultCache.ShouldBe(pendingFlashResult.Id.ToString()); + + await FlashSaleInventoryManager.Received() + .TryRollBackInventoryAsync(plan.TenantId, Product1.InventoryProviderName, plan.StoreId, plan.ProductId, plan.ProductSkuId, 1, true); + } + + [Fact] + public async Task HandleEventAsync_Should_Ignore_When_Success_Is_True() + { + var plan = await CreateFlashSalePlanAsync(); + var pendingFlashResult = await CreatePendingResultAsync(plan.Id, plan.StoreId, CurrentUser.GetId()); + var userFlashSaleResultCacheKey = string.Format(FlashSalePlanAppService.UserFlashSaleResultCacheKeyFormat, plan.TenantId, plan.Id, CurrentUser.GetId()); + await DistributedCache.SetStringAsync(userFlashSaleResultCacheKey, pendingFlashResult.Id.ToString()); + var createFlashSaleOrderCompleteEto = new CreateFlashSaleOrderCompleteEto() + { + TenantId = pendingFlashResult.TenantId, + PendingResultId = pendingFlashResult.Id, + Success = true, + StoreId = pendingFlashResult.StoreId, + PlanId = pendingFlashResult.PlanId, + OrderId = Guid.NewGuid(), + Reason = null, + UserId = pendingFlashResult.UserId + }; + + await EventHandler.HandleEventAsync(createFlashSaleOrderCompleteEto); + + var userFlashSaleResultCache = await DistributedCache.GetStringAsync(userFlashSaleResultCacheKey); + userFlashSaleResultCache.ShouldBe(pendingFlashResult.Id.ToString()); + + await FlashSaleInventoryManager.DidNotReceiveWithAnyArgs() + .TryRollBackInventoryAsync(default, default, Guid.Empty, Guid.Empty, Guid.Empty, default, default); + } + + [Fact] + public async Task HandleEventAsync_Should_Ignore_When_Reason_Not_InvalidHashToken() + { + var plan = await CreateFlashSalePlanAsync(); + var pendingFlashResult = await CreatePendingResultAsync(plan.Id, plan.StoreId, CurrentUser.GetId()); + var userFlashSaleResultCacheKey = string.Format(FlashSalePlanAppService.UserFlashSaleResultCacheKeyFormat, plan.TenantId, plan.Id, CurrentUser.GetId()); + await DistributedCache.SetStringAsync(userFlashSaleResultCacheKey, pendingFlashResult.Id.ToString()); + var createFlashSaleOrderCompleteEto = new CreateFlashSaleOrderCompleteEto() + { + TenantId = pendingFlashResult.TenantId, + PendingResultId = pendingFlashResult.Id, + Success = false, + StoreId = pendingFlashResult.StoreId, + PlanId = pendingFlashResult.PlanId, + OrderId = null, + Reason = "Other", + UserId = pendingFlashResult.UserId + }; + + await EventHandler.HandleEventAsync(createFlashSaleOrderCompleteEto); + + var userFlashSaleResultCache = await DistributedCache.GetStringAsync(userFlashSaleResultCacheKey); + userFlashSaleResultCache.ShouldBe(pendingFlashResult.Id.ToString()); + + await FlashSaleInventoryManager.DidNotReceiveWithAnyArgs() + .TryRollBackInventoryAsync(default, default, Guid.Empty, Guid.Empty, Guid.Empty, default, default); + } +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationTestBase.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationTestBase.cs index 77224ae3..e0877a3d 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationTestBase.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationTestBase.cs @@ -1,9 +1,149 @@ -namespace EasyAbp.EShop.Plugins.FlashSales; +using System.Threading.Tasks; +using System; +using EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; +using EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults; +using Volo.Abp; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Timing; +using Volo.Abp.Users; +using EasyAbp.EShop.Products.Products.Dtos; +using EasyAbp.EShop.Products.Products; +using System.Collections.Generic; + +namespace EasyAbp.EShop.Plugins.FlashSales; /* Inherit from this class for your application layer tests. * See SampleAppService_Tests for example. */ -public abstract class FlashSalesApplicationTestBase : FlashSalesTestBase +public abstract class FlashSalesApplicationTestBase : FlashSalesTestBase { + protected IGuidGenerator GuidGenerator { get; } + + protected ICurrentTenant CurrentTenant { get; } + + protected IClock Clock { get; } + + protected ICurrentUser CurrentUser { get; } + + protected IFlashSaleResultRepository FlashSaleResultRepository { get; } + + protected IFlashSalePlanRepository FlashSalePlanRepository { get; } + + protected FlashSalesApplicationTestBase() + { + GuidGenerator = GetRequiredService(); + CurrentTenant = GetRequiredService(); + Clock = GetRequiredService(); + CurrentUser = GetRequiredService(); + FlashSalePlanRepository = GetRequiredService(); + FlashSaleResultRepository = GetRequiredService(); + } + + protected virtual ProductDto CreateMockProductDto() + { + return new ProductDto + { + CreationTime = DateTime.Now, + IsPublished = true, + Id = FlashSalesTestData.Product1Id, + StoreId = FlashSalesTestData.Store1Id, + ProductGroupName = "Default", + ProductGroupDisplayName = "Default", + UniqueName = "Pencil", + DisplayName = "Hello pencil", + ProductDetailId = FlashSalesTestData.ProductDetail1Id, + ProductSkus = new List + { + new ProductSkuDto + { + Id = FlashSalesTestData.ProductSku1Id, + Name = "My SKU", + OrderMinQuantity = 0, + OrderMaxQuantity = 100, + AttributeOptionIds = new List(), + Price = 1m, + Currency = "USD", + ProductDetailId = null, + Inventory = 10, + }, + new ProductSkuDto + { + Id = FlashSalesTestData.ProductSku2Id, + Name = "My SKU 2", + OrderMinQuantity = 0, + OrderMaxQuantity = 100, + AttributeOptionIds = new List(), + Price = 2m, + Currency = "USD", + ProductDetailId = FlashSalesTestData.ProductDetail2Id, + Inventory = 0 + }, + new ProductSkuDto + { + Id = FlashSalesTestData.ProductSku3Id, + Name = "My SKU 3", + OrderMinQuantity = 0, + OrderMaxQuantity = 100, + AttributeOptionIds = new List(), + Price = 3m, + Currency = "USD", + ProductDetailId = FlashSalesTestData.ProductDetail2Id, + Inventory = 1 + } + }, + InventoryStrategy = InventoryStrategy.FlashSales, + LastModificationTime = FlashSalesTestData.ProductLastModificationTime + }; + } + + protected virtual async Task CreatePendingResultAsync(Guid planId, Guid storeId, Guid userId) + { + return await WithUnitOfWorkAsync(async () => + { + return await FlashSaleResultRepository.InsertAsync( + new FlashSaleResult(GuidGenerator.Create(), CurrentTenant.Id, storeId, planId, userId) + ); + }); + } + + protected virtual async Task CreateFlashSalePlanAsync(bool useSku2 = false, CreateTimeRange timeRange = CreateTimeRange.Starting, bool isPublished = true) + { + DateTime beginTime; + DateTime endTime; + + switch (timeRange) + { + case CreateTimeRange.Starting: + beginTime = Clock.Now; + endTime = beginTime.AddMinutes(30); + break; + case CreateTimeRange.NotStart: + beginTime = Clock.Now.AddMinutes(10); + endTime = beginTime.AddMinutes(30); + break; + case CreateTimeRange.Expired: + beginTime = Clock.Now.AddDays(-1); + endTime = beginTime.AddMinutes(30); + break; + case CreateTimeRange.WillBeExpired: + beginTime = Clock.Now.AddDays(-30); + endTime = Clock.Now.AddSeconds(1); + break; + default: + throw new AbpException(); + } + var flashSalePlan = new FlashSalePlan( + GuidGenerator.Create(), + CurrentTenant.Id, + FlashSalesTestData.Store1Id, + beginTime, + endTime, + FlashSalesTestData.Product1Id, + useSku2 ? FlashSalesTestData.ProductSku2Id : FlashSalesTestData.ProductSku1Id, + isPublished + ); + return await WithUnitOfWorkAsync(async () => await FlashSalePlanRepository.InsertAsync(flashSalePlan, autoSave: true)); + } } diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Products/Products/FakeFlashSaleInventoryManager.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Products/Products/FakeFlashSaleInventoryManager.cs new file mode 100644 index 00000000..ff159deb --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Products/Products/FakeFlashSaleInventoryManager.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading.Tasks; +using EasyAbp.Eshop.Products.Products; + +namespace EasyAbp.EShop.Products.Products; + +public class FakeFlashSaleInventoryManager : IFlashSaleInventoryManager +{ + public static bool ShouldReduceSuccess { get; set; } + + public FakeFlashSaleInventoryManager() + { + ShouldReduceSuccess = true; + } + + public Task TryReduceInventoryAsync( + Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool increaseSold) + { + return Task.FromResult(ShouldReduceSuccess); + } + + public Task TryRollBackInventoryAsync( + Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool decreaseSold) + { + return Task.FromResult(true); + } +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesDomainTestModule.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesDomainTestModule.cs similarity index 71% rename from plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesDomainTestModule.cs rename to plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesDomainTestModule.cs index 3a218f7f..3a033be8 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesDomainTestModule.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesDomainTestModule.cs @@ -8,9 +8,9 @@ namespace EasyAbp.EShop.Plugins.FlashSales; * database independent anyway. */ [DependsOn( - typeof(FlashSalesEntityFrameworkCoreTestModule) + typeof(EShopPluginsFlashSalesEntityFrameworkCoreTestModule) )] -public class FlashSalesDomainTestModule : AbpModule +public class EShopPluginsFlashSalesDomainTestModule : AbpModule { } diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanHasherTests.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanHasherTests.cs new file mode 100644 index 00000000..b0868cd8 --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanHasherTests.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; +public class FlashSalePlanHasherTests : FlashSalesDomainTestBase +{ + protected IFlashSalePlanHasher FlashSalePlanHasher { get; } + + public FlashSalePlanHasherTests() + { + FlashSalePlanHasher = GetRequiredService(); + } + + [Fact] + public async Task HashAsync() + { + var time1 = DateTime.Now; + var time2 = DateTime.Now.AddTicks(10); + var time3 = DateTime.Now.AddTicks(20); + + (await FlashSalePlanHasher.HashAsync(time1, time2, time3)) + .ShouldBe(await FlashSalePlanHasher.HashAsync(time1, time2, time3)); + } +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanTests.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanTests.cs new file mode 100644 index 00000000..90b7694b --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanTests.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; + +public class FlashSalePlanTests +{ + [Fact] + public void Should_Throw_InvalidEndTimeException() + { + Assert.Throws(() => + { + new FlashSalePlan( + id: Guid.NewGuid(), + tenantId: null, + storeId: Guid.NewGuid(), + beginTime: DateTime.Now, + endTime: DateTime.Now.AddSeconds(-1), + productId: Guid.NewGuid(), + productSkuId: Guid.NewGuid(), + isPublished: true + ); + }); + } + + [Fact] + public void SetTimeRange() + { + var existPlan = new FlashSalePlan( + id: Guid.NewGuid(), + tenantId: null, + storeId: Guid.NewGuid(), + beginTime: DateTime.Now, + endTime: DateTime.Now.AddSeconds(1), + productId: Guid.NewGuid(), + productSkuId: Guid.NewGuid(), + isPublished: true + ); + + var newBeginTime = DateTime.Now; + var newEndTime = newBeginTime.AddMinutes(1); + + existPlan.SetTimeRange(newBeginTime, newEndTime); + + existPlan.BeginTime.ShouldBe(newBeginTime); + existPlan.EndTime.ShouldBe(newEndTime); + } + + [Fact] + public void SetTimeRange_Should_Throw_InvalidEndTimeException_When_Set_InvalidEndTime() + { + var existPlan = new FlashSalePlan( + id: Guid.NewGuid(), + tenantId: null, + storeId: Guid.NewGuid(), + beginTime: DateTime.Now, + endTime: DateTime.Now.AddSeconds(1), + productId: Guid.NewGuid(), + productSkuId: Guid.NewGuid(), + isPublished: true + ); + + Assert.Throws(() => existPlan.SetTimeRange(DateTime.Now, DateTime.Now.AddMinutes(-1))); + } + + [Fact] + public void SetProductSku() + { + var existPlan = new FlashSalePlan( + id: Guid.NewGuid(), + tenantId: null, + storeId: Guid.NewGuid(), + beginTime: DateTime.Now, + endTime: DateTime.Now.AddSeconds(1), + productId: Guid.NewGuid(), + productSkuId: Guid.NewGuid(), + isPublished: true + ); + + var newStoreId = Guid.NewGuid(); + var newProductId = Guid.NewGuid(); + var newProductSkuId = Guid.NewGuid(); + + existPlan.SetProductSku(newStoreId, newProductId, newProductSkuId); + + existPlan.StoreId.ShouldBe(newStoreId); + existPlan.ProductId.ShouldBe(newProductId); + existPlan.ProductSkuId.ShouldBe(newProductSkuId); + } + + [Fact] + public void SetPublished() + { + var existPlan = new FlashSalePlan( + id: Guid.NewGuid(), + tenantId: null, + storeId: Guid.NewGuid(), + beginTime: DateTime.Now, + endTime: DateTime.Now.AddSeconds(1), + productId: Guid.NewGuid(), + productSkuId: Guid.NewGuid(), + isPublished: true + ); + + existPlan.SetPublished(false); + + existPlan.IsPublished.ShouldBe(false); + } +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/CreateFlashSaleOrderCompleteEventHandlerTests.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/CreateFlashSaleOrderCompleteEventHandlerTests.cs new file mode 100644 index 00000000..5172e23f --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/CreateFlashSaleOrderCompleteEventHandlerTests.cs @@ -0,0 +1,85 @@ +using System.Threading.Tasks; +using EasyAbp.EShop.Plugins.FlashSales.FlashSalePlans; +using Shouldly; +using Volo.Abp.Guids; +using Xunit; + +namespace EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults; + +public class CreateFlashSaleOrderCompleteEventHandlerTests : FlashSalesDomainTestBase +{ + protected IFlashSaleResultRepository FlashSaleResultRepository { get; } + protected CreateFlashSaleOrderCompleteEventHandler CreateFlashSaleOrderCompleteEventHandler { get; } + protected IGuidGenerator GuidGenerator { get; } + + public CreateFlashSaleOrderCompleteEventHandlerTests() + { + FlashSaleResultRepository = GetRequiredService(); + CreateFlashSaleOrderCompleteEventHandler = GetRequiredService(); + GuidGenerator = GetRequiredService(); + } + + [Fact] + public async Task HandleEventAsync_When_Create_Order_Success() + { + var existFlashResult = await CreateFlashSaleResultAsync(); + var createFlashSaleOrderCompleteEto = new CreateFlashSaleOrderCompleteEto() + { + TenantId = existFlashResult.TenantId, + PendingResultId = existFlashResult.Id, + Success = true, + StoreId = existFlashResult.StoreId, + PlanId = existFlashResult.PlanId, + OrderId = GuidGenerator.Create(), + Reason = null, + UserId = existFlashResult.UserId, + }; + + await CreateFlashSaleOrderCompleteEventHandler.HandleEventAsync(createFlashSaleOrderCompleteEto); + + var flashResult = await FlashSaleResultRepository.GetAsync(existFlashResult.Id); + flashResult.Status.ShouldBe(FlashSaleResultStatus.Successful); + flashResult.OrderId.ShouldBe(createFlashSaleOrderCompleteEto.OrderId); + flashResult.Reason.ShouldBe(null); + } + + [Fact] + public async Task HandleEventAsync_When_Create_Order_Failed() + { + var existFlashResult = await CreateFlashSaleResultAsync(); + var createFlashSaleOrderCompleteEto = new CreateFlashSaleOrderCompleteEto() + { + TenantId = existFlashResult.TenantId, + PendingResultId = existFlashResult.Id, + Success = false, + StoreId = FlashSalesTestData.Store1Id, + PlanId = existFlashResult.PlanId, + OrderId = null, + Reason = "Failed reason", + UserId = existFlashResult.UserId, + }; + + await CreateFlashSaleOrderCompleteEventHandler.HandleEventAsync(createFlashSaleOrderCompleteEto); + + var flashResult = await FlashSaleResultRepository.GetAsync(existFlashResult.Id); + flashResult.Status.ShouldBe(FlashSaleResultStatus.Failed); + flashResult.OrderId.ShouldBe(null); + flashResult.Reason.ShouldBe("Failed reason"); + } + + public async Task CreateFlashSaleResultAsync() + { + return await WithUnitOfWorkAsync(async () => + { + var flashSaleResult = new FlashSaleResult( + GuidGenerator.Create(), + null, + FlashSalesTestData.Store1Id, + FlashSalesTestData.Plan1Id, + GuidGenerator.Create()); + await FlashSaleResultRepository.InsertAsync(flashSaleResult); + + return flashSaleResult; + }); + } +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultTests.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultTests.cs new file mode 100644 index 00000000..7464ce4b --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSaleResults/FlashSaleResultTests.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Shouldly; +using Xunit; + +namespace EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults; + +public class FlashSaleResultTests +{ + [Fact] + public void MarkAsSuccessful() + { + var flashSaleResult = new FlashSaleResult( + id: Guid.NewGuid(), + tenantId: null, + storeId: Guid.NewGuid(), + planId: Guid.NewGuid(), + userId: Guid.NewGuid() + ); + + flashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Pending); + + var orderId = Guid.NewGuid(); + flashSaleResult.MarkAsSuccessful(orderId); + + flashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Successful); + flashSaleResult.OrderId.ShouldBe(orderId); + } + + [Fact] + public void MarkAsSuccessful_Should_Throw_FlashSaleResultStatusNotPendingException_When_Status_Not_Pending() + { + var flashSaleResult = new FlashSaleResult( + id: Guid.NewGuid(), + tenantId: null, + storeId: Guid.NewGuid(), + planId: Guid.NewGuid(), + userId: Guid.NewGuid() + ); + + flashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Pending); + + var orderId = Guid.NewGuid(); + flashSaleResult.MarkAsSuccessful(orderId); + flashSaleResult.Reason.ShouldBe(null); + + Assert.Throws(() => + { + flashSaleResult.MarkAsSuccessful(orderId); + }); + } + + [Fact] + public void MarkAsFailed() + { + var flashSaleResult = new FlashSaleResult( + id: Guid.NewGuid(), + tenantId: null, + storeId: Guid.NewGuid(), + planId: Guid.NewGuid(), + userId: Guid.NewGuid() + ); + + flashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Pending); + + flashSaleResult.MarkAsFailed("reason"); + + flashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Failed); + flashSaleResult.OrderId.ShouldBe(null); + flashSaleResult.Reason.ShouldBe("reason"); + } + + [Fact] + public void MarkAsFailed_Should_Throw_FlashSaleResultStatusNotPendingException_When_Status_Not_Pending() + { + var flashSaleResult = new FlashSaleResult( + id: Guid.NewGuid(), + tenantId: null, + storeId: Guid.NewGuid(), + planId: Guid.NewGuid(), + userId: Guid.NewGuid() + ); + + flashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Pending); + + flashSaleResult.MarkAsFailed("reason"); + + Assert.Throws(() => + { + flashSaleResult.MarkAsFailed("reason"); + }); + } +} diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesDomainTestBase.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesDomainTestBase.cs index 1cb6e93a..58e775a1 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesDomainTestBase.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Domain.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesDomainTestBase.cs @@ -3,7 +3,7 @@ /* Inherit from this class for your domain layer tests. * See SampleManager_Tests for example. */ -public abstract class FlashSalesDomainTestBase : FlashSalesTestBase +public abstract class FlashSalesDomainTestBase : FlashSalesTestBase { } diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesEntityFrameworkCoreTestModule.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/EShopPluginsFlashSalesEntityFrameworkCoreTestModule.cs similarity index 91% rename from plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesEntityFrameworkCoreTestModule.cs rename to plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/EShopPluginsFlashSalesEntityFrameworkCoreTestModule.cs index fb28fd4a..39b1283c 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesEntityFrameworkCoreTestModule.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/EShopPluginsFlashSalesEntityFrameworkCoreTestModule.cs @@ -9,11 +9,11 @@ using Volo.Abp.Modularity; namespace EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore; [DependsOn( - typeof(FlashSalesTestBaseModule), + typeof(EShopPluginsFlashSalesTestBaseModule), typeof(EShopPluginsFlashSalesEntityFrameworkCoreModule), typeof(AbpEntityFrameworkCoreSqliteModule) )] -public class FlashSalesEntityFrameworkCoreTestModule : AbpModule +public class EShopPluginsFlashSalesEntityFrameworkCoreTestModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesEntityFrameworkCoreTestBase.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesEntityFrameworkCoreTestBase.cs index 01e83ba7..0ba954e8 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesEntityFrameworkCoreTestBase.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesEntityFrameworkCoreTestBase.cs @@ -3,7 +3,7 @@ /* This class can be used as a base class for EF Core integration tests, * while SampleRepository_Tests uses a different approach. */ -public abstract class FlashSalesEntityFrameworkCoreTestBase : FlashSalesTestBase +public abstract class FlashSalesEntityFrameworkCoreTestBase : FlashSalesTestBase { } diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/ConsoleTestAppHostedService.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/ConsoleTestAppHostedService.cs index d9e47d1d..f1d41e9b 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/ConsoleTestAppHostedService.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/ConsoleTestAppHostedService.cs @@ -18,7 +18,7 @@ public class ConsoleTestAppHostedService : IHostedService public async Task StartAsync(CancellationToken cancellationToken) { - using (var application = await AbpApplicationFactory.CreateAsync(options => + using (var application = await AbpApplicationFactory.CreateAsync(options => { options.Services.ReplaceConfiguration(_configuration); options.UseAutofac(); diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/FlashSalesConsoleApiClientModule.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesConsoleApiClientModule.cs similarity index 80% rename from plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/FlashSalesConsoleApiClientModule.cs rename to plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesConsoleApiClientModule.cs index 1d081c6c..80a95f2c 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/FlashSalesConsoleApiClientModule.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesConsoleApiClientModule.cs @@ -9,7 +9,7 @@ namespace EasyAbp.EShop.Plugins.FlashSales; typeof(EShopPluginsFlashSalesHttpApiClientModule), typeof(AbpHttpClientIdentityModelModule) )] -public class FlashSalesConsoleApiClientModule : AbpModule +public class EShopPluginsFlashSalesConsoleApiClientModule : AbpModule { } diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbTestModule.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/EShopPluginsFlashSalesMongoDbTestModule.cs similarity index 86% rename from plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbTestModule.cs rename to plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/EShopPluginsFlashSalesMongoDbTestModule.cs index 2d101fa3..3bc8bcd3 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbTestModule.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/EShopPluginsFlashSalesMongoDbTestModule.cs @@ -6,10 +6,10 @@ using Volo.Abp.Uow; namespace EasyAbp.EShop.Plugins.FlashSales.MongoDB; [DependsOn( - typeof(FlashSalesTestBaseModule), + typeof(EShopPluginsFlashSalesTestBaseModule), typeof(EShopPluginsFlashSalesMongoDbModule) )] -public class FlashSalesMongoDbTestModule : AbpModule +public class EShopPluginsFlashSalesMongoDbTestModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbTestBase.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbTestBase.cs index 0953ae82..585e5ef6 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbTestBase.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbTestBase.cs @@ -3,7 +3,7 @@ /* This class can be used as a base class for MongoDB integration tests, * while SampleRepository_Tests uses a different approach. */ -public abstract class FlashSalesMongoDbTestBase : FlashSalesTestBase +public abstract class FlashSalesMongoDbTestBase : FlashSalesTestBase { } diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.TestBase/EasyAbp/EShop/Plugins/FlashSales/FlashSalesTestBaseModule.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.TestBase/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesTestBaseModule.cs similarity index 94% rename from plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.TestBase/EasyAbp/EShop/Plugins/FlashSales/FlashSalesTestBaseModule.cs rename to plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.TestBase/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesTestBaseModule.cs index 33ce5497..5bc24871 100644 --- a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.TestBase/EasyAbp/EShop/Plugins/FlashSales/FlashSalesTestBaseModule.cs +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.TestBase/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesTestBaseModule.cs @@ -14,7 +14,7 @@ namespace EasyAbp.EShop.Plugins.FlashSales; typeof(AbpAuthorizationModule), typeof(EShopPluginsFlashSalesDomainModule) )] -public class FlashSalesTestBaseModule : AbpModule +public class EShopPluginsFlashSalesTestBaseModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { diff --git a/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.TestBase/EasyAbp/EShop/Plugins/FlashSales/FlashSalesTestData.cs b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.TestBase/EasyAbp/EShop/Plugins/FlashSales/FlashSalesTestData.cs new file mode 100644 index 00000000..baa98bd9 --- /dev/null +++ b/plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.TestBase/EasyAbp/EShop/Plugins/FlashSales/FlashSalesTestData.cs @@ -0,0 +1,28 @@ +using System; + +namespace EasyAbp.EShop.Plugins.FlashSales; + +public static class FlashSalesTestData +{ + public static Guid Plan1Id { get; } = Guid.NewGuid(); + + public static Guid Result1Id { get; } = Guid.NewGuid(); + + public static Guid Store1Id { get; } = Guid.NewGuid(); + + public static Guid Product1Id { get; } = Guid.NewGuid(); + + public static Guid ProductSku1Id { get; } = Guid.NewGuid(); + + public static Guid ProductSku2Id { get; } = Guid.NewGuid(); + + public static Guid ProductSku3Id { get; } = Guid.NewGuid(); + + public static Guid ProductDetail1Id { get; } = Guid.NewGuid(); + + public static Guid ProductDetail2Id { get; } = Guid.NewGuid(); + + public static DateTime ProductLastModificationTime { get; } = DateTime.Today; + + public static DateTime ProductDetailLastModificationTime { get; } = DateTime.Today; +}