RuleConfigServiceTests.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using Admin.NET.Plugin.AiDOP.Rule;
  2. using Xunit;
  3. namespace Admin.NET.Plugin.AiDOP.Tests.Rule;
  4. public class RuleConfigServiceTests
  5. {
  6. [Fact]
  7. public async Task ResolveOptionsAsync_WhenNoConfiguredLayers_ReturnsDefaults()
  8. {
  9. var service = new RuleConfigService();
  10. var defaults = new S3DeliveryGenerateRuleOptions
  11. {
  12. QuotaRequiredTotal = 99m,
  13. DefaultLeadDays = 2,
  14. EnableExternalPushTracking = true
  15. };
  16. var result = await service.ResolveOptionsAsync("S3", "DELIVERY_GENERATE", 1000, 2000, defaults);
  17. Assert.True(result.Success);
  18. Assert.Equal(99m, result.Options.QuotaRequiredTotal);
  19. Assert.Equal(2, result.Options.DefaultLeadDays);
  20. Assert.True(result.Options.EnableExternalPushTracking);
  21. Assert.Empty(result.AppliedItems);
  22. }
  23. [Fact]
  24. public async Task ResolveS3DeliveryGenerateOptionsAsync_WhenNoConfiguredLayers_ReturnsS3Defaults()
  25. {
  26. var service = new RuleConfigService();
  27. var result = await service.ResolveS3DeliveryGenerateOptionsAsync(1000, 2000);
  28. Assert.True(result.Success);
  29. Assert.Equal(100m, result.Options.QuotaRequiredTotal);
  30. Assert.Equal(0.0001m, result.Options.QuotaTolerance);
  31. Assert.Equal(new[] { "110", "160", "170" }, result.Options.PoBuyerCodes);
  32. Assert.Equal(new[] { "标准", "VMI", "委外加工" }, result.Options.DoUsages);
  33. Assert.Equal(1, result.Options.DefaultLeadDays);
  34. Assert.True(result.Options.EnablePackagingRoundUp);
  35. Assert.True(result.Options.ShortageCreatePr);
  36. Assert.True(result.Options.EnablePrMerge);
  37. Assert.True(result.Options.EnableRequireGoodsToPo);
  38. Assert.True(result.Options.EnableExternalPushTracking);
  39. }
  40. [Fact]
  41. public async Task ResolveOptionsAsync_WhenRepositoryReturnsLayers_AppliesConfiguredRules()
  42. {
  43. var service = new RuleConfigService(new InMemoryRuleConfigRepository(new[]
  44. {
  45. new RuleConfigLayer
  46. {
  47. Scope = "global",
  48. Priority = 100,
  49. Items = new List<RuleConfigItem>
  50. {
  51. new() { RuleCode = "defaultLeadDays", ValueType = "number", RuleValue = "3" },
  52. new() { RuleCode = "enableExternalPushTracking", ValueType = "boolean", RuleValue = "false" }
  53. }
  54. }
  55. }));
  56. var result = await service.ResolveS3DeliveryGenerateOptionsAsync(1000, 2000);
  57. Assert.True(result.Success);
  58. Assert.Equal(3, result.Options.DefaultLeadDays);
  59. Assert.False(result.Options.EnableExternalPushTracking);
  60. Assert.Equal(2, result.AppliedItems.Count);
  61. }
  62. [Fact]
  63. public async Task ResolveOptionsAsync_WhenCancellationRequested_Throws()
  64. {
  65. var service = new RuleConfigService();
  66. using var cts = new CancellationTokenSource();
  67. await cts.CancelAsync();
  68. await Assert.ThrowsAsync<OperationCanceledException>(() =>
  69. service.ResolveOptionsAsync("S3", "DELIVERY_GENERATE", 1000, null, new S3DeliveryGenerateRuleOptions(), cts.Token));
  70. }
  71. [Fact]
  72. public async Task CreateSnapshot_WhenNoAppliedItems_UsesDefaultSource()
  73. {
  74. var service = new RuleConfigService();
  75. var resolvedAt = new DateTime(2026, 5, 16, 12, 0, 0);
  76. var result = await service.ResolveS3DeliveryGenerateOptionsAsync(1000, 2000);
  77. var snapshot = service.CreateSnapshot("S3", "DELIVERY_GENERATE", 1000, 2000, result, resolvedAt);
  78. Assert.Equal("S3", snapshot.ModuleCode);
  79. Assert.Equal("DELIVERY_GENERATE", snapshot.ScenarioCode);
  80. Assert.Equal("default", snapshot.Source);
  81. Assert.Equal(resolvedAt, snapshot.ResolvedAt);
  82. Assert.Equal(1000, snapshot.TenantId);
  83. Assert.Equal(2000, snapshot.FactoryId);
  84. Assert.Same(result.Options, snapshot.Options);
  85. Assert.Empty(snapshot.AppliedItems);
  86. Assert.Empty(snapshot.Warnings);
  87. }
  88. [Fact]
  89. public async Task CreateSnapshot_WhenAppliedItemsExist_UsesConfiguredSource()
  90. {
  91. var service = new RuleConfigService(new InMemoryRuleConfigRepository(new[]
  92. {
  93. new RuleConfigLayer
  94. {
  95. Scope = "factory",
  96. Priority = 300,
  97. Items = new List<RuleConfigItem>
  98. {
  99. new() { RuleCode = "defaultLeadDays", ValueType = "number", RuleValue = "5" }
  100. }
  101. }
  102. }));
  103. var result = await service.ResolveS3DeliveryGenerateOptionsAsync(1000, 2000);
  104. var snapshot = service.CreateSnapshot("S3", "DELIVERY_GENERATE", 1000, 2000, result, DateTime.Now);
  105. Assert.Equal("configured", snapshot.Source);
  106. Assert.Single(snapshot.AppliedItems);
  107. Assert.Equal(5, snapshot.Options.DefaultLeadDays);
  108. }
  109. [Fact]
  110. public async Task ResolveS3DeliveryGenerateSnapshotAsync_ReturnsSnapshot()
  111. {
  112. var service = new RuleConfigService(new InMemoryRuleConfigRepository(new[]
  113. {
  114. new RuleConfigLayer
  115. {
  116. Scope = "global",
  117. Priority = 100,
  118. Items = new List<RuleConfigItem>
  119. {
  120. new() { RuleCode = "defaultLeadDays", ValueType = "number", RuleValue = "4" }
  121. }
  122. }
  123. }));
  124. var resolvedAt = new DateTime(2026, 5, 16, 13, 30, 0);
  125. var snapshot = await service.ResolveS3DeliveryGenerateSnapshotAsync(1000, null, resolvedAt);
  126. Assert.Equal("S3", snapshot.ModuleCode);
  127. Assert.Equal("DELIVERY_GENERATE", snapshot.ScenarioCode);
  128. Assert.Equal("configured", snapshot.Source);
  129. Assert.Equal(resolvedAt, snapshot.ResolvedAt);
  130. Assert.Equal(1000, snapshot.TenantId);
  131. Assert.Null(snapshot.FactoryId);
  132. Assert.Equal(4, snapshot.Options.DefaultLeadDays);
  133. Assert.Single(snapshot.AppliedItems);
  134. }
  135. private sealed class InMemoryRuleConfigRepository : IRuleConfigRepository
  136. {
  137. private readonly IReadOnlyList<RuleConfigLayer> _layers;
  138. public InMemoryRuleConfigRepository(IReadOnlyList<RuleConfigLayer> layers)
  139. {
  140. _layers = layers;
  141. }
  142. public Task<IReadOnlyList<RuleConfigLayer>> GetEffectiveLayersAsync(
  143. string moduleCode,
  144. string scenarioCode,
  145. long tenantId,
  146. long? factoryId,
  147. CancellationToken cancellationToken = default)
  148. {
  149. cancellationToken.ThrowIfCancellationRequested();
  150. _ = moduleCode;
  151. _ = scenarioCode;
  152. _ = tenantId;
  153. _ = factoryId;
  154. return Task.FromResult(_layers);
  155. }
  156. }
  157. }