From cd2b65f8ed1886f637ed25e45c87d4f22fe70bc2 Mon Sep 17 00:00:00 2001 From: gdlcf88 Date: Sat, 11 Jun 2022 23:46:27 +0800 Subject: [PATCH] Orleans Grains inventory provider plugin --- Directory.Build.props | 1 + EShop.sln | 44 +++++++ .../inventories/orleans-grains/README.md | 58 ++++++++++ plugins/Inventories/OrleansGrains/README.md | 1 + ...entories.OrleansGrains.Abstractions.csproj | 18 +++ ...entoriesOrleansGrainsAbstractionsModule.cs | 11 ++ .../OrleansGrains/IInventoryGrain.cs | 13 +++ .../OrleansGrains/InventoryStateModel.cs | 8 ++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++ ...gins.Inventories.OrleansGrains.Silo.csproj | 18 +++ ...uginsInventoriesOrleansGrainsSiloModule.cs | 14 +++ ...p.Plugins.Inventories.OrleansGrains.csproj | 18 +++ ...opPluginsInventoriesOrleansGrainsModule.cs | 10 ++ .../OrleansGrains/InventoryGrain.cs | 68 +++++++++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++ ...ducts.OrleansGrainsInventory.Domain.csproj | 19 +++ ...ductsOrleansGrainsInventoryDomainModule.cs | 28 +++++ .../IInventoryGrainProvider.cs | 9 ++ .../InventoryGrainProvider.cs | 21 ++++ .../OrleansGrainsProductInventoryProvider.cs | 109 ++++++++++++++++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 +++++ ...sOrleansGrainsInventoryDomainTestModule.cs | 16 +++ ...OrleansGrainsInventory.Domain.Tests.csproj | 24 ++++ .../FakeInventoryGrain.cs | 43 +++++++ ...eansGrainsProductInventoryProviderTests.cs | 48 ++++++++ .../ProductsOrleansGrainsInventoryTestBase.cs | 61 ++++++++++ .../TestInventoryGrainProvider.cs | 25 ++++ 30 files changed, 784 insertions(+) create mode 100644 docs/plugins/inventories/orleans-grains/README.md create mode 120000 plugins/Inventories/OrleansGrains/README.md create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.csproj create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsAbstractionsModule.cs create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryStateModel.cs create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xml create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xsd create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo.csproj create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsSiloModule.cs create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xml create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xsd create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.csproj create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/EShopProductsOrleansGrainsInventoryDomainModule.cs create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/IInventoryGrainProvider.cs create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/InventoryGrainProvider.cs create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xml create mode 100644 plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xsd create mode 100644 plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EShopProductsOrleansGrainsInventoryDomainTestModule.cs create mode 100644 plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests.csproj create mode 100644 plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs create mode 100644 plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/OrleansGrainsProductInventoryProviderTests.cs create mode 100644 plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/ProductsOrleansGrainsInventoryTestBase.cs create mode 100644 plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/TestInventoryGrainProvider.cs diff --git a/Directory.Build.props b/Directory.Build.props index 99c2facf..7f008f29 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,6 +6,7 @@ 2.0.11 0.8.2 1.7.0 + 3.6.2 \ No newline at end of file diff --git a/EShop.sln b/EShop.sln index cd7f5691..98b9f223 100644 --- a/EShop.sln +++ b/EShop.sln @@ -359,6 +359,22 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Products.Dapr EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Plugins.Inventories.DaprActors.AspNetCore", "plugins\Inventories\DaprActors\src\EasyAbp.EShop.Plugins.Inventories.DaprActors.AspNetCore\EasyAbp.EShop.Plugins.Inventories.DaprActors.AspNetCore.csproj", "{3F0EA314-CCF4-4BB2-A8C1-79FAE4442884}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Plugins.Inventories.OrleansGrains", "plugins\Inventories\OrleansGrains\src\EasyAbp.EShop.Plugins.Inventories.OrleansGrains\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj", "{83F6434F-74DC-4389-870D-46510E28C029}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OrleansGrains", "OrleansGrains", "{88D17635-75D7-48A1-B622-E6FB3DCACEF8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8E978749-7972-4703-8A94-6A90080C78DE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions", "plugins\Inventories\OrleansGrains\src\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.csproj", "{AB3477DB-3457-4167-A086-BAD104D69604}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo", "plugins\Inventories\OrleansGrains\src\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo\EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo.csproj", "{0D613460-A0AD-4EAF-B719-785FE65E97E8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Products.OrleansGrainsInventory.Domain", "plugins\Inventories\OrleansGrains\src\EasyAbp.EShop.Products.OrleansGrainsInventory.Domain\EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.csproj", "{DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F58B6EEF-5AFF-4B79-BC71-A2D8C71F5E77}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests", "plugins\Inventories\OrleansGrains\test\EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests\EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests.csproj", "{D652EBF0-27CA-44C2-BB78-F446B87377C7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -933,6 +949,26 @@ Global {3F0EA314-CCF4-4BB2-A8C1-79FAE4442884}.Debug|Any CPU.Build.0 = Debug|Any CPU {3F0EA314-CCF4-4BB2-A8C1-79FAE4442884}.Release|Any CPU.ActiveCfg = Release|Any CPU {3F0EA314-CCF4-4BB2-A8C1-79FAE4442884}.Release|Any CPU.Build.0 = Release|Any CPU + {83F6434F-74DC-4389-870D-46510E28C029}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {83F6434F-74DC-4389-870D-46510E28C029}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83F6434F-74DC-4389-870D-46510E28C029}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83F6434F-74DC-4389-870D-46510E28C029}.Release|Any CPU.Build.0 = Release|Any CPU + {AB3477DB-3457-4167-A086-BAD104D69604}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB3477DB-3457-4167-A086-BAD104D69604}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB3477DB-3457-4167-A086-BAD104D69604}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB3477DB-3457-4167-A086-BAD104D69604}.Release|Any CPU.Build.0 = Release|Any CPU + {0D613460-A0AD-4EAF-B719-785FE65E97E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0D613460-A0AD-4EAF-B719-785FE65E97E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0D613460-A0AD-4EAF-B719-785FE65E97E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0D613460-A0AD-4EAF-B719-785FE65E97E8}.Release|Any CPU.Build.0 = Release|Any CPU + {DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD}.Release|Any CPU.Build.0 = Release|Any CPU + {D652EBF0-27CA-44C2-BB78-F446B87377C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D652EBF0-27CA-44C2-BB78-F446B87377C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D652EBF0-27CA-44C2-BB78-F446B87377C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D652EBF0-27CA-44C2-BB78-F446B87377C7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1112,6 +1148,14 @@ Global {485204B1-7603-4EA0-B3A4-73CB89B0D5BC} = {6E6FE4B9-4117-4F57-B219-EE47E4046096} {733C51A3-19C8-45C4-8B22-3FD40CAF4EFB} = {485204B1-7603-4EA0-B3A4-73CB89B0D5BC} {3F0EA314-CCF4-4BB2-A8C1-79FAE4442884} = {F468A386-5660-4888-981A-6ECF15182D32} + {88D17635-75D7-48A1-B622-E6FB3DCACEF8} = {9AC27747-E175-487F-92C9-434DEE543273} + {8E978749-7972-4703-8A94-6A90080C78DE} = {88D17635-75D7-48A1-B622-E6FB3DCACEF8} + {83F6434F-74DC-4389-870D-46510E28C029} = {8E978749-7972-4703-8A94-6A90080C78DE} + {AB3477DB-3457-4167-A086-BAD104D69604} = {8E978749-7972-4703-8A94-6A90080C78DE} + {0D613460-A0AD-4EAF-B719-785FE65E97E8} = {8E978749-7972-4703-8A94-6A90080C78DE} + {DB1C55BF-0C0D-488C-9AFC-992A3DED2EAD} = {8E978749-7972-4703-8A94-6A90080C78DE} + {F58B6EEF-5AFF-4B79-BC71-A2D8C71F5E77} = {88D17635-75D7-48A1-B622-E6FB3DCACEF8} + {D652EBF0-27CA-44C2-BB78-F446B87377C7} = {F58B6EEF-5AFF-4B79-BC71-A2D8C71F5E77} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {28315BFD-90E7-4E14-A2EA-F3D23AF4126F} diff --git a/docs/plugins/inventories/orleans-grains/README.md b/docs/plugins/inventories/orleans-grains/README.md new file mode 100644 index 00000000..c72baf83 --- /dev/null +++ b/docs/plugins/inventories/orleans-grains/README.md @@ -0,0 +1,58 @@ +# EShop.Plugins.Inventories.OrleansGrains + +[![ABP version](https://img.shields.io/badge/dynamic/xml?style=flat-square&color=yellow&label=abp&query=%2F%2FProject%2FPropertyGroup%2FAbpVersion&url=https%3A%2F%2Fraw.githubusercontent.com%2FEasyAbp%2FEShop%2Fmaster%2FDirectory.Build.props)](https://abp.io) +[![NuGet](https://img.shields.io/nuget/v/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.svg?style=flat-square)](https://www.nuget.org/packages/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions) +[![NuGet Download](https://img.shields.io/nuget/dt/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.svg?style=flat-square)](https://www.nuget.org/packages/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions) +[![Discord online](https://badgen.net/discord/online-members/S6QaezrCRq?label=Discord)](https://discord.gg/S6QaezrCRq) +[![GitHub stars](https://img.shields.io/github/stars/EasyAbp/EShop?style=social)](https://www.github.com/EasyAbp/EShop) + +EShop product-inventory implementation of [Orleans Grains](https://docs.microsoft.com/en-us/dotnet/orleans/grains). + +## Installation + +1. Install the following NuGet packages. ([see how](https://github.com/EasyAbp/EasyAbpGuide/blob/master/docs/How-To.md#add-nuget-packages)) + + * EasyAbp.EShop.Products.OrleansGrainsInventory.Domain _(install at EasyAbp.EShop.Products.Domain location)_ + * EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo _(install at a host project to run Grains)_ + +2. Add `DependsOn(typeof(EShopXxxModule))` attribute to configure the module dependencies. ([see how](https://github.com/EasyAbp/EasyAbpGuide/blob/master/docs/How-To.md#add-module-dependencies)) + +3. Open `Program.cs` in the host project to create an Orleans Silo. (see Microsoft's [document](https://docs.microsoft.com/en-us/dotnet/orleans/host/configuration-guide/server-configuration) for more information) + + ```csharp + builder.Host.AddAppSettingsSecretsJson() + .UseAutofac() + .UseSerilog() + .UseOrleans(c => + { + c.UseLocalhostClustering() // for test only + .AddMemoryGrainStorage(InventoryGrain.StorageProviderName) // for test only + .Configure(options => + { + options.ClusterId = "my-first-cluster"; + options.ServiceId = "MyEShopApp"; + }) + .ConfigureApplicationParts( + parts => parts.AddApplicationPart(typeof(InventoryGrain).Assembly).WithReferences()); + }); + ``` + +## Usage + +1. Configure the OrleansGrains inventory provider as default. + ```csharp + Configure(options => + { + // Configure as the default inventory provider + options.DefaultInventoryProviderName = "OrleansGrains"; + + // Configure as the default inventory provider for MyProductGroup + options.Groups.Configure(group => + { + group.DefaultInventoryProviderName = "OrleansGrains"; + }); + }); + ``` + > Better to use `OrleansGrainsProductInventoryProvider.OrleansGrainsProductInventoryProviderName` instead of `"OrleansGrains"` as the provider name. + +2. Create a product and set `InventoryProviderName` to `OrleansGrains`. Then the product is specified to use the Orleans Grains inventory provider. \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/README.md b/plugins/Inventories/OrleansGrains/README.md new file mode 120000 index 00000000..1dd0889c --- /dev/null +++ b/plugins/Inventories/OrleansGrains/README.md @@ -0,0 +1 @@ +../../../docs/plugins/inventories/orleans-grains/README.md \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.csproj b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.csproj new file mode 100644 index 00000000..c15ef67d --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions.csproj @@ -0,0 +1,18 @@ + + + + + + net6.0 + + + + + + + + + + + + diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsAbstractionsModule.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsAbstractionsModule.cs new file mode 100644 index 00000000..a327dd08 --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsAbstractionsModule.cs @@ -0,0 +1,11 @@ +using EasyAbp.EShop.Products; +using Volo.Abp.Modularity; + +namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains; + +[DependsOn( + typeof(EShopProductsDomainSharedModule) +)] +public class EShopPluginsInventoriesOrleansGrainsAbstractionsModule : AbpModule +{ +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs new file mode 100644 index 00000000..7deb1fe6 --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/IInventoryGrain.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; +using Orleans; + +namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains; + +public interface IInventoryGrain : IGrainWithStringKey +{ + Task GetInventoryStateAsync(); + + Task IncreaseInventoryAsync(int quantity, bool decreaseSold); + + Task ReduceInventoryAsync(int quantity, bool increaseSold); +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryStateModel.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryStateModel.cs new file mode 100644 index 00000000..5d7482ec --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryStateModel.cs @@ -0,0 +1,8 @@ +namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains; + +public class InventoryStateModel +{ + public int Inventory { get; set; } + + public long Sold { get; set; } +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xml b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xml new file mode 100644 index 00000000..1715698c --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xsd b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/FodyWeavers.xsd new file mode 100644 index 00000000..ffa6fc4b --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Abstractions/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/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo.csproj b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo.csproj new file mode 100644 index 00000000..5d010900 --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo.csproj @@ -0,0 +1,18 @@ + + + + + + net6.0 + + + + + + + + + + + + diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsSiloModule.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsSiloModule.cs new file mode 100644 index 00000000..6d974fdf --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.Silo/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsSiloModule.cs @@ -0,0 +1,14 @@ +using EasyAbp.EShop.Products; +using Volo.Abp.Modularity; + +namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains; + +[DependsOn( + typeof(EShopPluginsInventoriesOrleansGrainsModule) +)] +public class EShopPluginsInventoriesOrleansGrainsSiloModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + } +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj new file mode 100644 index 00000000..5e949e66 --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp.EShop.Plugins.Inventories.OrleansGrains.csproj @@ -0,0 +1,18 @@ + + + + + + net6.0 + + + + + + + + + + + + diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs new file mode 100644 index 00000000..087bb7b9 --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/EShopPluginsInventoriesOrleansGrainsModule.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Modularity; + +namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains; + +[DependsOn( + typeof(EShopPluginsInventoriesOrleansGrainsAbstractionsModule) +)] +public class EShopPluginsInventoriesOrleansGrainsModule : AbpModule +{ +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs new file mode 100644 index 00000000..454fdb86 --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/EasyAbp/EShop/Plugins/Inventories/OrleansGrains/InventoryGrain.cs @@ -0,0 +1,68 @@ +using System.Threading.Tasks; +using Orleans; +using Orleans.Providers; +using Orleans.Runtime; + +namespace EasyAbp.EShop.Plugins.Inventories.OrleansGrains; + +[StorageProvider(ProviderName = StorageProviderName)] +public class InventoryGrain : Grain, IInventoryGrain +{ + public const string StorageProviderName = "EShopInventoryStorage"; + + public virtual Task GetInventoryStateAsync() => Task.FromResult(State); + + public virtual async Task IncreaseInventoryAsync(int quantity, bool decreaseSold) + { + InternalIncreaseInventory(quantity, decreaseSold); + + await WriteStateAsync(); + } + + public async Task ReduceInventoryAsync(int quantity, bool increaseSold) + { + InternalReduceInventory(quantity, increaseSold); + + await WriteStateAsync(); + } + + protected virtual void InternalIncreaseInventory(int quantity, bool decreaseSold) + { + if (quantity < 0) + { + throw new OrleansException("Quantity should not be less than 0."); + } + + if (decreaseSold && State.Sold - quantity < 0) + { + throw new OrleansException("Target Sold cannot be less than 0."); + } + + State.Inventory = checked(State.Inventory + quantity); + + if (decreaseSold) + { + State.Sold -= quantity; + } + } + + protected virtual void InternalReduceInventory(int quantity, bool increaseSold) + { + if (quantity < 0) + { + throw new OrleansException("Quantity should not be less than 0."); + } + + if (quantity > State.Inventory) + { + throw new OrleansException("Insufficient inventory."); + } + + if (increaseSold) + { + State.Sold = checked(State.Sold + quantity); + } + + State.Inventory -= quantity; + } +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xml b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xml new file mode 100644 index 00000000..1715698c --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xsd b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/FodyWeavers.xsd new file mode 100644 index 00000000..ffa6fc4b --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Plugins.Inventories.OrleansGrains/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/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.csproj b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.csproj new file mode 100644 index 00000000..708e1aa1 --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.csproj @@ -0,0 +1,19 @@ + + + + + + net6.0 + + + + + + + + + + + + + diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/EShopProductsOrleansGrainsInventoryDomainModule.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/EShopProductsOrleansGrainsInventoryDomainModule.cs new file mode 100644 index 00000000..84838e9b --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/EShopProductsOrleansGrainsInventoryDomainModule.cs @@ -0,0 +1,28 @@ +using EasyAbp.EShop.Plugins.Inventories.OrleansGrains; +using EasyAbp.EShop.Products.Options; +using Volo.Abp.Modularity; + +namespace EasyAbp.EShop.Products.OrleansGrainsInventory; + +[DependsOn( + typeof(EShopProductsDomainModule), + typeof(EShopPluginsInventoriesOrleansGrainsAbstractionsModule) +)] +public class EShopProductsOrleansGrainsInventoryDomainModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.InventoryProviders.Configure( + OrleansGrainsProductInventoryProvider.OrleansGrainsProductInventoryProviderName, provider => + { + provider.DisplayName = + OrleansGrainsProductInventoryProvider.OrleansGrainsProductInventoryProviderDisplayName; + provider.Description = OrleansGrainsProductInventoryProvider + .OrleansGrainsProductInventoryProviderDescription; + provider.ProviderType = typeof(OrleansGrainsProductInventoryProvider); + }); + }); + } +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/IInventoryGrainProvider.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/IInventoryGrainProvider.cs new file mode 100644 index 00000000..5f5d1966 --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/IInventoryGrainProvider.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; +using EasyAbp.EShop.Plugins.Inventories.OrleansGrains; + +namespace EasyAbp.EShop.Products.OrleansGrainsInventory; + +public interface IInventoryGrainProvider +{ + Task GetAsync(string grainKey); +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/InventoryGrainProvider.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/InventoryGrainProvider.cs new file mode 100644 index 00000000..0ef6d00f --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/InventoryGrainProvider.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using EasyAbp.EShop.Plugins.Inventories.OrleansGrains; +using Orleans; +using Volo.Abp.DependencyInjection; + +namespace EasyAbp.EShop.Products.OrleansGrainsInventory; + +public class InventoryGrainProvider : IInventoryGrainProvider, ITransientDependency +{ + private readonly IGrainFactory _grainFactory; + + public InventoryGrainProvider(IGrainFactory grainFactory) + { + _grainFactory = grainFactory; + } + + public virtual Task GetAsync(string grainKey) + { + return Task.FromResult(_grainFactory.GetGrain(grainKey)); + } +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs new file mode 100644 index 00000000..54a95b54 --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/EasyAbp/EShop/Products/OrleansGrainsInventory/OrleansGrainsProductInventoryProvider.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using EasyAbp.EShop.Plugins.Inventories.OrleansGrains; +using EasyAbp.EShop.Products.ProductInventories; +using Microsoft.Extensions.Logging; +using Volo.Abp.DependencyInjection; + +namespace EasyAbp.EShop.Products.OrleansGrainsInventory; + +public class OrleansGrainsProductInventoryProvider : IProductInventoryProvider, ITransientDependency +{ + public static string OrleansGrainsProductInventoryProviderName { get; set; } = "OrleansGrains"; + public static string OrleansGrainsProductInventoryProviderDisplayName { get; set; } = "OrleansGrains"; + public static string OrleansGrainsProductInventoryProviderDescription { get; set; } = "OrleansGrains"; + + public string InventoryProviderName { get; } = OrleansGrainsProductInventoryProviderName; + + private readonly ILogger _logger; + protected IInventoryGrainProvider InventoryGrainProvider { get; } + + public OrleansGrainsProductInventoryProvider( + IInventoryGrainProvider inventoryGrainProvider, + ILogger logger) + { + InventoryGrainProvider = inventoryGrainProvider; + _logger = logger; + } + + public virtual async Task GetInventoryDataAsync(InventoryQueryModel model) + { + var grain = await GetGrainAsync(model); + + var stateModel = await grain.GetInventoryStateAsync(); + + return new InventoryDataModel + { + Inventory = stateModel.Inventory, + Sold = stateModel.Sold + }; + } + + public virtual async Task> GetSkuIdInventoryDataMappingAsync( + IList models) + { + var result = new Dictionary(); + + foreach (var model in models) + { + result.Add(model.ProductSkuId, await GetInventoryDataAsync(model)); + } + + return result; + } + + public virtual async Task TryIncreaseInventoryAsync(InventoryQueryModel model, int quantity, + bool decreaseSold) + { + var grain = await GetGrainAsync(model); + + try + { + await grain.IncreaseInventoryAsync(quantity, decreaseSold); + } + catch (Exception e) + { + _logger.LogError("Grain threw: {Message}", e.Message); + + return false; + } + + return true; + } + + public virtual async Task TryReduceInventoryAsync(InventoryQueryModel model, int quantity, bool increaseSold) + { + var grain = await GetGrainAsync(model); + + var stateModel = await grain.GetInventoryStateAsync(); + + if (stateModel.Inventory < quantity) + { + return false; + } + + try + { + await grain.ReduceInventoryAsync(quantity, increaseSold); + } + catch (Exception e) + { + _logger.LogError("Grain threw: {Message}", e.Message); + + return false; + } + + return true; + } + + protected virtual async Task GetGrainAsync(InventoryQueryModel model) + { + return await InventoryGrainProvider.GetAsync(GetGrainId(model)); + } + + protected virtual string GetGrainId(InventoryQueryModel model) + { + return $"eshop_inventory_{(model.TenantId.HasValue ? model.TenantId.Value : "host")}_{model.ProductSkuId}"; + } +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xml b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xml new file mode 100644 index 00000000..1715698c --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xsd b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/FodyWeavers.xsd new file mode 100644 index 00000000..ffa6fc4b --- /dev/null +++ b/plugins/Inventories/OrleansGrains/src/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain/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/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EShopProductsOrleansGrainsInventoryDomainTestModule.cs b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EShopProductsOrleansGrainsInventoryDomainTestModule.cs new file mode 100644 index 00000000..38074ed7 --- /dev/null +++ b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EShopProductsOrleansGrainsInventoryDomainTestModule.cs @@ -0,0 +1,16 @@ +using Volo.Abp; +using Volo.Abp.Authorization; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace EasyAbp.EShop.Products.OrleansGrainsInventory.Domain; + +[DependsOn( + typeof(AbpAutofacModule), + typeof(AbpTestBaseModule), + typeof(AbpAuthorizationModule), + typeof(EShopProductsOrleansGrainsInventoryDomainModule) +)] +public class EShopProductsOrleansGrainsInventoryDomainTestModule : AbpModule +{ +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests.csproj b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests.csproj new file mode 100644 index 00000000..ee834e1b --- /dev/null +++ b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests.csproj @@ -0,0 +1,24 @@ + + + + net6.0 + EasyAbp.EShop.Products.OrleansGrainsInventory.Domain + + + + + + + + + + + + + + + + + + + diff --git a/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs new file mode 100644 index 00000000..49f7199a --- /dev/null +++ b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/FakeInventoryGrain.cs @@ -0,0 +1,43 @@ +using System.Threading.Tasks; +using EasyAbp.EShop.Plugins.Inventories.OrleansGrains; +using Volo.Abp.DependencyInjection; + +namespace EasyAbp.EShop.Products.OrleansGrainsInventory.Domain; + +public class FakeInventoryGrain : IInventoryGrain, ITransientDependency +{ + private InventoryStateModel StateModel { get; } = new() + { + Inventory = 100, + Sold = 0 + }; + + public Task GetInventoryStateAsync() + { + return Task.FromResult(StateModel); + } + + public Task IncreaseInventoryAsync(int quantity, bool decreaseSold) + { + StateModel.Inventory += quantity; + + if (decreaseSold) + { + StateModel.Sold -= quantity; + } + + return Task.CompletedTask; + } + + public Task ReduceInventoryAsync(int quantity, bool increaseSold) + { + StateModel.Inventory -= quantity; + + if (increaseSold) + { + StateModel.Sold += quantity; + } + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/OrleansGrainsProductInventoryProviderTests.cs b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/OrleansGrainsProductInventoryProviderTests.cs new file mode 100644 index 00000000..3570b22c --- /dev/null +++ b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/OrleansGrainsProductInventoryProviderTests.cs @@ -0,0 +1,48 @@ +using System.Threading.Tasks; +using EasyAbp.EShop.Products.ProductInventories; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Xunit; + +namespace EasyAbp.EShop.Products.OrleansGrainsInventory.Domain; + +public class OrleansGrainsProductInventoryProviderTests : ProductsOrleansGrainsInventoryTestBase +{ + [Fact] + public async Task Should_Get_Inventory() + { + var inventoryProvider = ServiceProvider.GetRequiredService(); + + var inventoryDataModel = await inventoryProvider.GetInventoryDataAsync(new InventoryQueryModel()); + + inventoryDataModel.ShouldNotBeNull(); + inventoryDataModel.Inventory.ShouldBe(100); + inventoryDataModel.Sold.ShouldBe(0); + } + + [Fact] + public async Task Should_Change_Inventory() + { + var inventoryProvider = ServiceProvider.GetRequiredService(); + + var result = await inventoryProvider.TryReduceInventoryAsync(new InventoryQueryModel(), 2, true); + + result.ShouldBeTrue(); + + var inventoryDataModel = await inventoryProvider.GetInventoryDataAsync(new InventoryQueryModel()); + + inventoryDataModel.ShouldNotBeNull(); + inventoryDataModel.Inventory.ShouldBe(98); + inventoryDataModel.Sold.ShouldBe(2); + + result = await inventoryProvider.TryIncreaseInventoryAsync(new InventoryQueryModel(), 1, true); + + result.ShouldBeTrue(); + + inventoryDataModel = await inventoryProvider.GetInventoryDataAsync(new InventoryQueryModel()); + + inventoryDataModel.ShouldNotBeNull(); + inventoryDataModel.Inventory.ShouldBe(99); + inventoryDataModel.Sold.ShouldBe(1); + } +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/ProductsOrleansGrainsInventoryTestBase.cs b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/ProductsOrleansGrainsInventoryTestBase.cs new file mode 100644 index 00000000..1830da9d --- /dev/null +++ b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/ProductsOrleansGrainsInventoryTestBase.cs @@ -0,0 +1,61 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.Abp.Modularity; +using Volo.Abp.Testing; +using Volo.Abp.Uow; + +namespace EasyAbp.EShop.Products.OrleansGrainsInventory.Domain +{ + /* All test classes are derived from this class, directly or indirectly. */ + public abstract class + ProductsOrleansGrainsInventoryTestBase : AbpIntegratedTest + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + + protected virtual Task WithUnitOfWorkAsync(Func func) + { + return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); + } + + protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func action) + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(options)) + { + await action(); + + await uow.CompleteAsync(); + } + } + } + + protected virtual Task WithUnitOfWorkAsync(Func> func) + { + return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); + } + + protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, + Func> func) + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(options)) + { + var result = await func(); + await uow.CompleteAsync(); + return result; + } + } + } + } +} \ No newline at end of file diff --git a/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/TestInventoryGrainProvider.cs b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/TestInventoryGrainProvider.cs new file mode 100644 index 00000000..42c9990e --- /dev/null +++ b/plugins/Inventories/OrleansGrains/test/EasyAbp.EShop.Products.OrleansGrainsInventory.Domain.Tests/TestInventoryGrainProvider.cs @@ -0,0 +1,25 @@ +using System; +using System.Threading.Tasks; +using EasyAbp.EShop.Plugins.Inventories.OrleansGrains; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.DependencyInjection; + +namespace EasyAbp.EShop.Products.OrleansGrainsInventory.Domain; + +[Dependency(ReplaceServices = true)] +public class TestInventoryGrainProvider : IInventoryGrainProvider, ITransientDependency +{ + private IInventoryGrain Grain { get; set; } + + private readonly IServiceProvider _serviceProvider; + + public TestInventoryGrainProvider(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + public Task GetAsync(string grainKey) + { + return Task.FromResult(Grain ??= _serviceProvider.GetRequiredService()); + } +} \ No newline at end of file