Browse Source

Fix flash-sales UTs

pull/223/head
Jadyn 4 years ago
parent
commit
b2327c9832
  1. 42
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandler.cs
  2. 31
      plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCreationResultEventHandler.cs
  3. 62
      plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs
  4. 7
      plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppServiceTests.cs
  5. 29
      plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Products/Products/FakeProductCache.cs

42
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandler.cs

@ -1,8 +1,7 @@
using System.Threading.Tasks;
using EasyAbp.Eshop.Products.Products;
using EasyAbp.EShop.Orders.Orders;
using EasyAbp.EShop.Plugins.FlashSales.FlashSaleResults;
using EasyAbp.EShop.Products.Products;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
@ -20,30 +19,14 @@ public class FlashSaleOrderCanceledEventHandler : IDistributedEventHandler<Order
protected IAbpApplication AbpApplication { get; }
protected IFlashSaleInventoryManager FlashSaleInventoryManager { get; }
protected IProductCache ProductCache { get; }
protected IFlashSaleCurrentResultCache FlashSaleCurrentResultCache { get; }
protected ILogger<FlashSaleOrderCanceledEventHandler> Logger { get; }
public FlashSaleOrderCanceledEventHandler(
IFlashSaleResultRepository flashSaleResultRepository,
IUnitOfWorkManager unitOfWorkManager,
IAbpApplication abpApplication,
IFlashSaleInventoryManager flashSaleInventoryManager,
IProductCache productCache,
IFlashSaleCurrentResultCache flashSaleCurrentResultCache,
ILogger<FlashSaleOrderCanceledEventHandler> logger)
IAbpApplication abpApplication)
{
FlashSaleResultRepository = flashSaleResultRepository;
UnitOfWorkManager = unitOfWorkManager;
AbpApplication = abpApplication;
FlashSaleInventoryManager = flashSaleInventoryManager;
ProductCache = productCache;
FlashSaleCurrentResultCache = flashSaleCurrentResultCache;
Logger = logger;
}
[UnitOfWork(true)]
@ -62,25 +45,10 @@ public class FlashSaleOrderCanceledEventHandler : IDistributedEventHandler<Order
UnitOfWorkManager.Current.OnCompleted(async () =>
{
if (eventData.Order.OrderLines.Count == 0)
{
Logger.LogWarning("OrderCanceled order {orderId} orderLines is empty.", eventData.Order.Id);
return;
}
var productId = eventData.Order.OrderLines[0].ProductId;
var productSkuId = eventData.Order.OrderLines[0].ProductSkuId;
var product = await ProductCache.GetAsync(productId);
// try to roll back the inventory.
if (!await FlashSaleInventoryManager.TryRollBackInventoryAsync(
eventData.TenantId, product.InventoryProviderName, eventData.Order.StoreId,
productId, productSkuId))
{
Logger.LogWarning("Failed to roll back the flash sale inventory.");
return; // avoid to remove cache if the rollback failed.
}
using var scope = AbpApplication.ServiceProvider.CreateScope();
var flashSaleCurrentResultCache = scope.ServiceProvider.GetRequiredService<IFlashSaleCurrentResultCache>();
// remove the cache so the user can try to order again.
await FlashSaleCurrentResultCache.RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId);
await flashSaleCurrentResultCache.RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId);
});
}
}

31
plugins/FlashSales/src/EasyAbp.EShop.Plugins.FlashSales.Application/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCreationResultEventHandler.cs

@ -16,28 +16,19 @@ public class FlashSaleOrderCreationResultEventHandler : IDistributedEventHandler
ITransientDependency
{
protected ILogger<FlashSaleOrderCreationResultEventHandler> Logger { get; }
protected IFlashSaleInventoryManager FlashSaleInventoryManager { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IObjectMapper ObjectMapper { get; }
protected IAbpApplication AbpApplication { get; }
protected IFlashSaleCurrentResultCache FlashSaleCurrentResultCache { get; }
protected IFlashSaleResultRepository FlashSaleResultRepository { get; }
public FlashSaleOrderCreationResultEventHandler(
ILogger<FlashSaleOrderCreationResultEventHandler> logger,
IFlashSaleInventoryManager flashSaleInventoryManager,
IUnitOfWorkManager unitOfWorkManager,
IObjectMapper objectMapper,
IAbpApplication abpApplication,
IFlashSaleCurrentResultCache flashSaleCurrentResultCache,
IFlashSaleResultRepository flashSaleResultRepository)
{
Logger = logger;
FlashSaleInventoryManager = flashSaleInventoryManager;
UnitOfWorkManager = unitOfWorkManager;
ObjectMapper = objectMapper;
AbpApplication = abpApplication;
FlashSaleCurrentResultCache = flashSaleCurrentResultCache;
FlashSaleResultRepository = flashSaleResultRepository;
}
@ -61,14 +52,20 @@ public class FlashSaleOrderCreationResultEventHandler : IDistributedEventHandler
UnitOfWorkManager.Current.OnCompleted(async () =>
{
using var scope = AbpApplication.ServiceProvider.CreateScope();
var flashSaleInventoryManager = scope.ServiceProvider.GetRequiredService<IFlashSaleInventoryManager>();
var flashSaleCurrentResultCache = scope.ServiceProvider.GetRequiredService<IFlashSaleCurrentResultCache>();
var objectMapper = scope.ServiceProvider.GetRequiredService<IObjectMapper>();
if (eventData.Success)
{
await ResetFlashSaleCurrentResultCacheAsync(flashSaleResult);
await ResetFlashSaleCurrentResultCacheAsync(flashSaleResult, objectMapper, flashSaleCurrentResultCache);
}
else
{
// try to roll back the inventory.
if (!await FlashSaleInventoryManager.TryRollBackInventoryAsync(
if (!await flashSaleInventoryManager.TryRollBackInventoryAsync(
eventData.TenantId, eventData.ProductInventoryProviderName, eventData.StoreId,
eventData.ProductId, eventData.ProductSkuId))
{
@ -79,23 +76,19 @@ public class FlashSaleOrderCreationResultEventHandler : IDistributedEventHandler
// remove the cache so the user can try to order again.
if (eventData.AllowToTryAgain)
{
await FlashSaleCurrentResultCache.RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId);
await flashSaleCurrentResultCache.RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId);
}
else
{
await ResetFlashSaleCurrentResultCacheAsync(flashSaleResult);
await ResetFlashSaleCurrentResultCacheAsync(flashSaleResult, objectMapper, flashSaleCurrentResultCache);
}
}
});
}
protected virtual async Task ResetFlashSaleCurrentResultCacheAsync(FlashSaleResult flashSaleResult)
protected virtual async Task ResetFlashSaleCurrentResultCacheAsync(FlashSaleResult flashSaleResult,
IObjectMapper objectMapper, IFlashSaleCurrentResultCache flashSaleCurrentResultCache)
{
using var scope = AbpApplication.ServiceProvider.CreateScope();
var objectMapper = scope.ServiceProvider.GetRequiredService<IObjectMapper>();
var flashSaleCurrentResultCache = scope.ServiceProvider.GetRequiredService<IFlashSaleCurrentResultCache>();
await flashSaleCurrentResultCache.SetAsync(flashSaleResult.PlanId, flashSaleResult.UserId,
new FlashSaleCurrentResultCacheItem
{

62
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSaleOrderCanceledEventHandlerTests.cs

@ -21,15 +21,12 @@ public class FlashSaleOrderCanceledEventHandlerTests : FlashSalesApplicationTest
protected IFlashSaleCurrentResultCache FlashSaleCurrentResultCache { get; }
protected IFlashSaleInventoryManager FlashSaleInventoryManager { get; }
private ProductDto Product1 { get; set; }
public FlashSaleOrderCanceledEventHandlerTests()
{
ResultMarkAsFailedOrderCanceledEventHandler = GetRequiredService<FlashSaleOrderCanceledEventHandler>();
FlashSaleCurrentResultCache = GetRequiredService<IFlashSaleCurrentResultCache>();
FlashSaleInventoryManager = GetRequiredService<IFlashSaleInventoryManager>();
}
protected override void AfterAddApplication(IServiceCollection services)
@ -40,9 +37,6 @@ public class FlashSaleOrderCanceledEventHandlerTests : FlashSalesApplicationTest
productAppService.GetAsync(FlashSalesTestData.Product1Id).Returns(Task.FromResult(Product1));
services.Replace(ServiceDescriptor.Singleton(productAppService));
var flashSaleInventoryManager = Substitute.For<IFlashSaleInventoryManager>();
services.Replace(ServiceDescriptor.Singleton(flashSaleInventoryManager));
var flashSaleCurrentResultCache = Substitute.For<IFlashSaleCurrentResultCache>();
services.Replace(ServiceDescriptor.Singleton(flashSaleCurrentResultCache));
}
@ -65,11 +59,6 @@ public class FlashSaleOrderCanceledEventHandlerTests : FlashSalesApplicationTest
}
});
flashSaleResult = await MarkAsSuccessfulAsync(flashSaleResult.Id, orderCanceledEto.Order.Id);
FlashSaleInventoryManager
.TryRollBackInventoryAsync(flashSaleResult.TenantId,
Product1.InventoryProviderName, flashSaleResult.StoreId,
FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id)
.Returns(Task.FromResult(true));
await ResultMarkAsFailedOrderCanceledEventHandler.HandleEventAsync(orderCanceledEto);
@ -77,52 +66,10 @@ public class FlashSaleOrderCanceledEventHandlerTests : FlashSalesApplicationTest
existFlashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Failed);
existFlashSaleResult.Reason.ShouldBe(FlashSaleResultFailedReason.OrderCanceled);
await FlashSaleInventoryManager.Received()
.TryRollBackInventoryAsync(flashSaleResult.TenantId,
Product1.InventoryProviderName, flashSaleResult.StoreId,
FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id);
await FlashSaleCurrentResultCache.Received()
.RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId);
}
[Fact]
public async Task HandleEventAsync_Should_Not_RemoveResultCache_When_TryRollBackInventory_Failed()
{
var flashSaleResult = await CreateFlashSaleResultAsync();
var orderCanceledEto = new OrderCanceledEto(new OrderEto()
{
Id = Guid.NewGuid(),
StoreId = flashSaleResult.StoreId,
OrderLines = new List<OrderLineEto>()
{
new OrderLineEto()
{
ProductId = FlashSalesTestData.Product1Id,
ProductSkuId = FlashSalesTestData.ProductSku1Id
}
}
});
flashSaleResult = await MarkAsSuccessfulAsync(flashSaleResult.Id, orderCanceledEto.Order.Id);
FlashSaleInventoryManager
.TryRollBackInventoryAsync(flashSaleResult.TenantId,
Product1.InventoryProviderName, flashSaleResult.StoreId,
FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id)
.Returns(Task.FromResult(false));
await ResultMarkAsFailedOrderCanceledEventHandler.HandleEventAsync(orderCanceledEto);
var existFlashSaleResult = await FlashSaleResultRepository.GetAsync(flashSaleResult.Id);
existFlashSaleResult.Status.ShouldBe(FlashSaleResultStatus.Failed);
existFlashSaleResult.Reason.ShouldBe(FlashSaleResultFailedReason.OrderCanceled);
await FlashSaleInventoryManager.Received()
.TryRollBackInventoryAsync(flashSaleResult.TenantId,
Product1.InventoryProviderName, flashSaleResult.StoreId,
FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id);
await FlashSaleCurrentResultCache.DidNotReceive()
.RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId);
}
[Fact]
public async Task HandleEventAsync_Should_Skip_Handling_If_Result_Does_Not_Exist()
{
@ -142,11 +89,6 @@ public class FlashSaleOrderCanceledEventHandlerTests : FlashSalesApplicationTest
});
flashSaleResult = await MarkAsSuccessfulAsync(flashSaleResult.Id, orderCanceledEto.Order.Id);
flashSaleResult = await MarkAsFailedAsync(flashSaleResult.Id, "UT");
FlashSaleInventoryManager
.TryRollBackInventoryAsync(flashSaleResult.TenantId,
Product1.InventoryProviderName, flashSaleResult.StoreId,
FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id)
.Returns(Task.FromResult(true));
await ResultMarkAsFailedOrderCanceledEventHandler.HandleEventAsync(orderCanceledEto);
@ -154,10 +96,6 @@ public class FlashSaleOrderCanceledEventHandlerTests : FlashSalesApplicationTest
existFlashSaleResult.Status.ShouldBe(flashSaleResult.Status);
existFlashSaleResult.Reason.ShouldBe(flashSaleResult.Reason);
await FlashSaleInventoryManager.DidNotReceive()
.TryRollBackInventoryAsync(flashSaleResult.TenantId,
Product1.InventoryProviderName, flashSaleResult.StoreId,
FlashSalesTestData.Product1Id, FlashSalesTestData.ProductSku1Id);
await FlashSaleCurrentResultCache.DidNotReceive()
.RemoveAsync(flashSaleResult.PlanId, flashSaleResult.UserId);
}

7
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Plugins/FlashSales/FlashSalePlans/FlashSalePlanAppServiceTests.cs

@ -30,15 +30,12 @@ public class FlashSalePlanAppServiceTests : FlashSalesApplicationTestBase
protected IDistributedEventBus DistributedEventBus { get; }
protected IDistributedCache<ProductCacheItem, Guid> ProductDistributedCache { get; }
private ProductDto Product1 { get; set; }
public FlashSalePlanAppServiceTests()
{
AppService = GetRequiredService<FlashSalePlanAppService>();
DistributedEventBus = GetRequiredService<IDistributedEventBus>();
ProductDistributedCache = GetRequiredService<IDistributedCache<ProductCacheItem, Guid>>();
}
protected override void AfterAddApplication(IServiceCollection services)
@ -59,6 +56,8 @@ public class FlashSalePlanAppServiceTests : FlashSalesApplicationTestBase
info.AddOrUpdateProperty<string>("key1");
});
services.Replace(ServiceDescriptor.Transient<IProductCache, FakeProductCache>());
base.AfterAddApplication(services);
}
@ -338,13 +337,11 @@ public class FlashSalePlanAppServiceTests : FlashSalesApplicationTestBase
Product1.IsPublished = true;
Product1.InventoryStrategy = InventoryStrategy.ReduceAfterPlacing;
await ProductDistributedCache.RemoveAsync(Product1.Id);
await AppService.PreOrderAsync(plan.Id)
.ShouldThrowAsync<UnexpectedInventoryStrategyException>();
Product1.InventoryStrategy = InventoryStrategy.FlashSales;
await ProductDistributedCache.RemoveAsync(Product1.Id);
var plan2 = await CreateFlashSalePlanAsync(isPublished: false);
await AppService.PreOrderAsync(plan2.Id)

29
plugins/FlashSales/test/EasyAbp.EShop.Plugins.FlashSales.Application.Tests/EasyAbp/EShop/Products/Products/FakeProductCache.cs

@ -0,0 +1,29 @@
using System;
using System.Threading.Tasks;
using EasyAbp.EShop.Products.Products.Dtos;
using Volo.Abp.ObjectMapping;
namespace EasyAbp.EShop.Products.Products;
public class FakeProductCache : IProductCache
{
protected IProductAppService ProductAppService { get; }
protected IObjectMapper ObjectMapper { get; }
public FakeProductCache(IProductAppService productAppService, IObjectMapper objectMapper)
{
ProductAppService = productAppService;
ObjectMapper = objectMapper;
}
public async Task<ProductCacheItem> GetAsync(Guid productId)
{
var dto = await ProductAppService.GetAsync(productId);
return ObjectMapper.Map<ProductDto, ProductCacheItem>(dto);
}
public Task RemoveAsync(Guid productId)
{
return Task.CompletedTask;
}
}
Loading…
Cancel
Save