mirror of https://github.com/EasyAbp/EShop.git
29 changed files with 1515 additions and 17 deletions
@ -0,0 +1,3 @@ |
|||
{ |
|||
"role": "lib.test" |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\EasyAbp.EShop.Orders.Plugins.FlashSales.Application\EasyAbp.EShop.Orders.Plugins.FlashSales.Application.csproj" /> |
|||
<ProjectReference Include="..\EasyAbp.EShop.Plugins.FlashSales.TestBase\EasyAbp.EShop.Plugins.FlashSales.TestBase.csproj" /> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -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<CreateFlashSaleOrderEventHandler>(); |
|||
CurrentUser = GetRequiredService<ICurrentUser>(); |
|||
CurrentTenant = GetRequiredService<ICurrentTenant>(); |
|||
DistributedEventBus = GetRequiredService<IDistributedEventBus>(); |
|||
FlashSalePlanHasher = GetRequiredService<IFlashSalePlanHasher>(); |
|||
OrderRepository = GetRequiredService<IOrderRepository>(); |
|||
} |
|||
|
|||
protected override void AfterAddApplication(IServiceCollection services) |
|||
{ |
|||
Product1 = CreateMockProductDto(); |
|||
|
|||
var productAppService = Substitute.For<IProductAppService>(); |
|||
productAppService.GetAsync(FlashSalesTestData.Product1Id).Returns(Task.FromResult(Product1)); |
|||
services.Replace(ServiceDescriptor.Singleton(productAppService)); |
|||
|
|||
var productDetailAppService = Substitute.For<IProductDetailAppService>(); |
|||
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<IDistributedEventBus>(); |
|||
services.Replace(ServiceDescriptor.Singleton(distributedEventBus)); |
|||
|
|||
var flashSalePlanHasher = Substitute.For<IFlashSalePlanHasher>(); |
|||
services.Replace(ServiceDescriptor.Singleton(flashSalePlanHasher)); |
|||
|
|||
var orderRepository = Substitute.For<IOrderRepository>(); |
|||
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<Order>()); |
|||
|
|||
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<CreateFlashSaleOrderCompleteEto>(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<CreateFlashSaleOrderCompleteEto>(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 |
|||
)); |
|||
} |
|||
} |
|||
@ -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 |
|||
{ |
|||
|
|||
} |
|||
@ -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<EShopOrdersPluginsFlashSalesApplicationTestsModule> |
|||
{ |
|||
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<ProductSkuDto> |
|||
{ |
|||
new ProductSkuDto |
|||
{ |
|||
Id = FlashSalesTestData.ProductSku1Id, |
|||
Name = "My SKU", |
|||
OrderMinQuantity = 0, |
|||
OrderMaxQuantity = 100, |
|||
AttributeOptionIds = new List<Guid>(), |
|||
Price = 1m, |
|||
Currency = "USD", |
|||
ProductDetailId = null, |
|||
Inventory = 10, |
|||
}, |
|||
new ProductSkuDto |
|||
{ |
|||
Id = FlashSalesTestData.ProductSku2Id, |
|||
Name = "My SKU 2", |
|||
OrderMinQuantity = 0, |
|||
OrderMaxQuantity = 100, |
|||
AttributeOptionIds = new List<Guid>(), |
|||
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<Guid>(), |
|||
Price = 3m, |
|||
Currency = "USD", |
|||
ProductDetailId = FlashSalesTestData.ProductDetail2Id, |
|||
Inventory = 1 |
|||
} |
|||
}, |
|||
InventoryStrategy = InventoryStrategy.FlashSales, |
|||
LastModificationTime = FlashSalesTestData.ProductLastModificationTime |
|||
}; |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,9 @@ |
|||
namespace EasyAbp.EShop.Plugins.FlashSales; |
|||
|
|||
public enum CreateTimeRange |
|||
{ |
|||
Starting, |
|||
NotStart, |
|||
Expired, |
|||
WillBeExpired, |
|||
} |
|||
4
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationTestModule.cs → plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesApplicationTestModule.cs
4
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalesApplicationTestModule.cs → plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesApplicationTestModule.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<FlashSalePlanAppService>(); |
|||
DistributedEventBus = GetRequiredService<IDistributedEventBus>(); |
|||
} |
|||
|
|||
protected override void AfterAddApplication(IServiceCollection services) |
|||
{ |
|||
Product1 = CreateMockProductDto(); |
|||
|
|||
var productAppService = Substitute.For<IProductAppService>(); |
|||
productAppService.GetAsync(FlashSalesTestData.Product1Id).Returns(Task.FromResult(Product1)); |
|||
services.Replace(ServiceDescriptor.Singleton(productAppService)); |
|||
|
|||
services.Replace(ServiceDescriptor.Transient<IFlashSaleInventoryManager, FakeFlashSaleInventoryManager>()); |
|||
|
|||
var distributedEventBus = Substitute.For<IDistributedEventBus>(); |
|||
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<FlashSalePlanDto> 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<ProductIsNotInThisStoreException>(); |
|||
Product1.StoreId = FlashSalesTestData.Store1Id; |
|||
|
|||
Product1.InventoryStrategy = InventoryStrategy.ReduceAfterPlacing; |
|||
await AppService.CreateAsync(createDto).ShouldThrowAsync<UnexpectedInventoryStrategyException>(); |
|||
|
|||
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<ProductIsNotInThisStoreException>(); |
|||
Product1.StoreId = FlashSalesTestData.Store1Id; |
|||
|
|||
Product1.InventoryStrategy = InventoryStrategy.ReduceAfterPlacing; |
|||
await AppService.UpdateAsync(returnFlashSalePlanDto.Id, updateDto).ShouldThrowAsync<UnexpectedInventoryStrategyException>(); |
|||
|
|||
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<RelatedFlashSaleResultsExistException>(); |
|||
} |
|||
|
|||
[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<EntityNotFoundException>(); |
|||
} |
|||
|
|||
[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<RelatedFlashSaleResultsExistException>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task PreOrderAsync() |
|||
{ |
|||
var options = GetRequiredService<IOptions<FlashSalesOptions>>().Value; |
|||
var distributedCache = GetRequiredService<IDistributedCache<FlashSalePlanPreOrderCacheItem>>(); |
|||
var plan = await CreateFlashSalePlanAsync(); |
|||
var preOrderCacheKey = string.Format(FlashSalePlanAppService.PreOrderCacheKeyFormat, plan.Id, CurrentUser.Id); |
|||
var hashToken = await GetRequiredService<IFlashSalePlanHasher>() |
|||
.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<BusinessException>()) |
|||
.Code.ShouldBe(FlashSalesErrorCodes.ProductIsNotPublished); |
|||
|
|||
Product1.IsPublished = true; |
|||
|
|||
Product1.InventoryStrategy = InventoryStrategy.ReduceAfterPlacing; |
|||
|
|||
await AppService.PreOrderAsync(plan.Id) |
|||
.ShouldThrowAsync<UnexpectedInventoryStrategyException>(); |
|||
|
|||
Product1.InventoryStrategy = InventoryStrategy.FlashSales; |
|||
|
|||
var plan2 = await CreateFlashSalePlanAsync(isPublished: false); |
|||
await AppService.PreOrderAsync(plan2.Id) |
|||
.ShouldThrowAsync<EntityNotFoundException>(); |
|||
|
|||
var plan3 = await CreateFlashSalePlanAsync(timeRange: CreateTimeRange.Expired); |
|||
(await AppService.PreOrderAsync(plan3.Id) |
|||
.ShouldThrowAsync<BusinessException>()) |
|||
.Code.ShouldBe(FlashSalesErrorCodes.FlashSaleIsOver); |
|||
|
|||
var plan4 = await CreateFlashSalePlanAsync(useSku2: true); |
|||
(await AppService.PreOrderAsync(plan4.Id) |
|||
.ShouldThrowAsync<BusinessException>()) |
|||
.Code.ShouldBe(FlashSalesErrorCodes.ProductSkuInventoryExceeded); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task OrderAsync() |
|||
{ |
|||
var plan = await CreateFlashSalePlanAsync(); |
|||
var hashToken = await GetRequiredService<IFlashSalePlanHasher>() |
|||
.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<CreateFlashSaleOrderEto>(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<BusinessException>()) |
|||
.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<BusinessException>()) |
|||
.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<BusinessException>()) |
|||
.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<IAbpDistributedLock>(); |
|||
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<BusinessException>()) |
|||
.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<IDistributedCache>(); |
|||
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<BusinessException>()) |
|||
.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<ICurrentUser>().GetId(); |
|||
|
|||
await CreatePendingResultAsync(plan.Id, plan.StoreId, userId); |
|||
|
|||
(await AppService.OrderAsync(plan.Id, createOrderInput) |
|||
.ShouldThrowAsync<BusinessException>()) |
|||
.Code.ShouldBe(FlashSalesErrorCodes.DuplicateFlashSalesOrder); |
|||
} |
|||
} |
|||
@ -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<RollBackInventoryCreateFlashSaleOrderCompleteEventHandler>(); |
|||
DistributedCache = GetRequiredService<IDistributedCache>(); |
|||
FlashSaleInventoryManager = GetRequiredService<IFlashSaleInventoryManager>(); |
|||
} |
|||
|
|||
protected override void AfterAddApplication(IServiceCollection services) |
|||
{ |
|||
Product1 = CreateMockProductDto(); |
|||
|
|||
var productAppService = Substitute.For<IProductAppService>(); |
|||
productAppService.GetAsync(FlashSalesTestData.Product1Id).Returns(Task.FromResult(Product1)); |
|||
services.Replace(ServiceDescriptor.Singleton(productAppService)); |
|||
|
|||
FlashSaleInventoryManager = Substitute.For<IFlashSaleInventoryManager>(); |
|||
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); |
|||
} |
|||
} |
|||
@ -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<FlashSalesApplicationTestModule> |
|||
public abstract class FlashSalesApplicationTestBase : FlashSalesTestBase<EShopPluginsFlashSalesApplicationTestModule> |
|||
{ |
|||
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<IGuidGenerator>(); |
|||
CurrentTenant = GetRequiredService<ICurrentTenant>(); |
|||
Clock = GetRequiredService<IClock>(); |
|||
CurrentUser = GetRequiredService<ICurrentUser>(); |
|||
FlashSalePlanRepository = GetRequiredService<IFlashSalePlanRepository>(); |
|||
FlashSaleResultRepository = GetRequiredService<IFlashSaleResultRepository>(); |
|||
} |
|||
|
|||
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<ProductSkuDto> |
|||
{ |
|||
new ProductSkuDto |
|||
{ |
|||
Id = FlashSalesTestData.ProductSku1Id, |
|||
Name = "My SKU", |
|||
OrderMinQuantity = 0, |
|||
OrderMaxQuantity = 100, |
|||
AttributeOptionIds = new List<Guid>(), |
|||
Price = 1m, |
|||
Currency = "USD", |
|||
ProductDetailId = null, |
|||
Inventory = 10, |
|||
}, |
|||
new ProductSkuDto |
|||
{ |
|||
Id = FlashSalesTestData.ProductSku2Id, |
|||
Name = "My SKU 2", |
|||
OrderMinQuantity = 0, |
|||
OrderMaxQuantity = 100, |
|||
AttributeOptionIds = new List<Guid>(), |
|||
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<Guid>(), |
|||
Price = 3m, |
|||
Currency = "USD", |
|||
ProductDetailId = FlashSalesTestData.ProductDetail2Id, |
|||
Inventory = 1 |
|||
} |
|||
}, |
|||
InventoryStrategy = InventoryStrategy.FlashSales, |
|||
LastModificationTime = FlashSalesTestData.ProductLastModificationTime |
|||
}; |
|||
} |
|||
|
|||
protected virtual async Task<FlashSaleResult> 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<FlashSalePlan> 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)); |
|||
} |
|||
} |
|||
|
|||
@ -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<bool> TryReduceInventoryAsync( |
|||
Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool increaseSold) |
|||
{ |
|||
return Task.FromResult(ShouldReduceSuccess); |
|||
} |
|||
|
|||
public Task<bool> TryRollBackInventoryAsync( |
|||
Guid? tenantId, string providerName, Guid storeId, Guid productId, Guid productSkuId, int quantity, bool decreaseSold) |
|||
{ |
|||
return Task.FromResult(true); |
|||
} |
|||
} |
|||
@ -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<FlashSalePlanHasher>(); |
|||
} |
|||
|
|||
[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)); |
|||
} |
|||
} |
|||
@ -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<InvalidEndTimeException>(() => |
|||
{ |
|||
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<InvalidEndTimeException>(() => 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); |
|||
} |
|||
} |
|||
@ -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<IFlashSaleResultRepository>(); |
|||
CreateFlashSaleOrderCompleteEventHandler = GetRequiredService<CreateFlashSaleOrderCompleteEventHandler>(); |
|||
GuidGenerator = GetRequiredService<IGuidGenerator>(); |
|||
} |
|||
|
|||
[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<FlashSaleResult> CreateFlashSaleResultAsync() |
|||
{ |
|||
return await WithUnitOfWorkAsync(async () => |
|||
{ |
|||
var flashSaleResult = new FlashSaleResult( |
|||
GuidGenerator.Create(), |
|||
null, |
|||
FlashSalesTestData.Store1Id, |
|||
FlashSalesTestData.Plan1Id, |
|||
GuidGenerator.Create()); |
|||
await FlashSaleResultRepository.InsertAsync(flashSaleResult); |
|||
|
|||
return flashSaleResult; |
|||
}); |
|||
} |
|||
} |
|||
@ -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<FlashSaleResultStatusNotPendingException>(() => |
|||
{ |
|||
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<FlashSaleResultStatusNotPendingException>(() => |
|||
{ |
|||
flashSaleResult.MarkAsFailed("reason"); |
|||
}); |
|||
} |
|||
} |
|||
4
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesEntityFrameworkCoreTestModule.cs → plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/EShopPluginsFlashSalesEntityFrameworkCoreTestModule.cs
4
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/FlashSalesEntityFrameworkCoreTestModule.cs → plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.EntityFrameworkCore.Tests/EasyAbp/EShop/Plugins/FlashSales/EntityFrameworkCore/EShopPluginsFlashSalesEntityFrameworkCoreTestModule.cs
2
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/FlashSalesConsoleApiClientModule.cs → plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesConsoleApiClientModule.cs
2
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/FlashSalesConsoleApiClientModule.cs → plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.HttpApi.Client.ConsoleTestApp/EasyAbp/EShop/Plugins/FlashSales/EShopPluginsFlashSalesConsoleApiClientModule.cs
4
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbTestModule.cs → plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/EShopPluginsFlashSalesMongoDbTestModule.cs
4
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/FlashSalesMongoDbTestModule.cs → plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.MongoDB.Tests/EasyAbp/EShop/Plugins/FlashSales/MongoDB/EShopPluginsFlashSalesMongoDbTestModule.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; |
|||
} |
|||
Loading…
Reference in new issue