SmartDiagnosisEvidenceTests.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. using Admin.NET.Plugin.AiDOP.SmartOps;
  2. using Xunit;
  3. namespace Admin.NET.Plugin.AiDOP.Tests.SmartOps;
  4. public class SmartDiagnosisEvidenceTests
  5. {
  6. [Theory]
  7. [InlineData("S1", "order_schedule")]
  8. [InlineData("S3", "supplier_delivery")]
  9. [InlineData("S3", "material_readiness")]
  10. [InlineData("S4", "supplier_delivery")]
  11. [InlineData("S5", "iqc_bill")]
  12. [InlineData("S6", "s6_report")]
  13. [InlineData("S7", "fqc_result")]
  14. [InlineData("S8", "s8_exception")]
  15. public void Module_ResolvesRegisteredSource(string module, string sourceKey)
  16. {
  17. Assert.Contains(SmartDiagnosisEvidenceRegistry.Resolve(module), x => x.Key == sourceKey);
  18. }
  19. [Fact]
  20. public void S9_ReusesModuleSources_NotAThirdFactChain()
  21. {
  22. var s9 = SmartDiagnosisEvidenceRegistry.Resolve("S9");
  23. Assert.DoesNotContain(s9, x => x.Key == "s8_exception");
  24. Assert.Equal(
  25. SmartDiagnosisEvidenceRegistry.All.Count(
  26. x => x.Key != "s8_exception" && x.MetricCodes.Count == 0),
  27. s9.Count);
  28. Assert.Contains(s9, x => x.Domain == SmartDiagnosisEvidenceDomain.Delivery
  29. || x.Domain == SmartDiagnosisEvidenceDomain.Manufacturing);
  30. Assert.Contains(s9, x => x.Domain == SmartDiagnosisEvidenceDomain.Supply);
  31. Assert.Contains(s9, x => x.Domain == SmartDiagnosisEvidenceDomain.Quality);
  32. }
  33. [Theory]
  34. [InlineData("S1_L3_001")]
  35. [InlineData("S1_L3_105")]
  36. [InlineData("S1_L4_002")]
  37. [InlineData("S1_L4_104")]
  38. public void S1_ReviewMetric_ResolvesOnlyExplicitReviewFlowSource(string metricCode)
  39. {
  40. var sources = SmartDiagnosisEvidenceRegistry.ResolveMetric("S1", metricCode);
  41. var source = Assert.Single(sources);
  42. Assert.Equal("s1_contract_review_flow", source.Key);
  43. Assert.Contains("@metricCode", source.CountSql, StringComparison.Ordinal);
  44. Assert.Contains("@metricCode", source.ItemSql, StringComparison.Ordinal);
  45. }
  46. [Theory]
  47. [InlineData("S1_L4_202")]
  48. [InlineData("S1_L2_004")]
  49. [InlineData("S1_L1_001")]
  50. [InlineData("S3_L2_001")]
  51. [InlineData("S3_L2_002")]
  52. [InlineData("S3_L2_003")]
  53. [InlineData("S3_L2_006")]
  54. [InlineData("S3_L1_003")]
  55. [InlineData("S3_L1_004")]
  56. [InlineData("S4_L1_003")]
  57. [InlineData("S5_L1_003")]
  58. [InlineData("S5_L1_004")]
  59. [InlineData("S5_L2_003")]
  60. [InlineData("S5_L2_006")]
  61. [InlineData("S5_L3_001")]
  62. [InlineData("S5_L3_003")]
  63. [InlineData("S6_L1_001")]
  64. [InlineData("S6_L1_003")]
  65. [InlineData("S6_L2_003")]
  66. [InlineData("S6_L2_004")]
  67. [InlineData("S6_L3_007")]
  68. [InlineData("S7_L1_003")]
  69. [InlineData("S7_L2_001")]
  70. [InlineData("S7_L2_003")]
  71. [InlineData("S7_L2_004")]
  72. [InlineData("S9_L1_002")]
  73. [InlineData("S9_L1_003")]
  74. [InlineData("S9_L1_004")]
  75. [InlineData("S9_L1_005")]
  76. public void UnboundMetric_DoesNotFallBackToModuleEvidence(string metricCode)
  77. {
  78. var moduleCode = metricCode.Split('_')[0];
  79. Assert.Empty(SmartDiagnosisEvidenceRegistry.ResolveMetric(moduleCode, metricCode));
  80. }
  81. [Fact]
  82. public void MetricBinding_RejectsCrossModuleLookup()
  83. {
  84. Assert.Empty(SmartDiagnosisEvidenceRegistry.ResolveMetric("S3", "S1_L3_001"));
  85. }
  86. [Fact]
  87. public void UnknownModule_IsUnsupported()
  88. {
  89. Assert.Contains(SmartDiagnosisEvidenceRegistry.Resolve("S8"), x => x.Key == "s8_exception");
  90. Assert.Empty(SmartDiagnosisEvidenceRegistry.Resolve("XX"));
  91. }
  92. [Fact]
  93. public void EverySource_RequiresTenantParameter_AndForbidsClientSql()
  94. {
  95. foreach (var source in SmartDiagnosisEvidenceRegistry.All)
  96. {
  97. Assert.Contains("@tenantId", source.CountSql, StringComparison.Ordinal);
  98. Assert.Contains("@tenantId", source.ItemSql, StringComparison.Ordinal);
  99. if (source.CountSql.Contains("factory_id", StringComparison.OrdinalIgnoreCase))
  100. {
  101. Assert.Contains("factory_id=1", source.CountSql, StringComparison.Ordinal);
  102. Assert.Contains("factory_id<>@tenantId", source.CountSql, StringComparison.Ordinal);
  103. Assert.Contains("factory_id=1", source.ItemSql, StringComparison.Ordinal);
  104. }
  105. Assert.DoesNotContain("{", source.ItemSql);
  106. Assert.DoesNotContain("+", source.CountSql);
  107. if (source.MetricCodes.Count > 0)
  108. {
  109. Assert.Contains("@metricCode", source.CountSql, StringComparison.Ordinal);
  110. Assert.Contains("@metricCode", source.ItemSql, StringComparison.Ordinal);
  111. }
  112. foreach (var filter in source.Filters)
  113. {
  114. Assert.DoesNotContain(" ", filter.SqlColumn);
  115. Assert.DoesNotContain(";", filter.SqlColumn);
  116. Assert.Matches("^[a-z0-9_]+$", filter.SqlColumn);
  117. }
  118. if (!string.IsNullOrWhiteSpace(source.DateColumn))
  119. Assert.Matches("^[a-zA-Z0-9_]+(\\.[a-zA-Z0-9_]+)?$", source.DateColumn);
  120. if (!string.IsNullOrWhiteSpace(source.DrillQueryKey))
  121. Assert.Matches("^[a-zA-Z0-9_]+$", source.DrillQueryKey);
  122. }
  123. }
  124. [Theory]
  125. [InlineData("S2", "S2_L2_002", "s2_order_schedule_metric", "/aidop/s2/production-scheduling/work-order-scheduling")]
  126. [InlineData("S2", "S2_L3_002", "s2_operation_schedule_metric", "/aidop/s2/operation-plan/executable-daily-plan")]
  127. [InlineData("S3", "S3_L3_006", "s3_material_readiness_metric", "/aidop/s3/supply-kanban/work-order-material-readiness")]
  128. [InlineData("S3", "S3_L3_001", "s3_purchase_request_metric", "/aidop/s3/procurement/purchase-request")]
  129. [InlineData("S3", "S3_L3_002", "s3_purchase_order_metric", "/aidop/s3/procurement/purchase-order")]
  130. [InlineData("S3", "S3_L3_004", "s3_delivery_schedule_metric", "/aidop/s3/material-plan/delivery-schedule")]
  131. [InlineData("S3", "S3_L3_005", "s3_supplier_delivery_metric", "/aidop/s3/procurement/purchase-order")]
  132. [InlineData("S4", "S4_L3_002", "s4_supplier_delivery_metric", "/aidop/s4/delivery/supplier-delivery-management")]
  133. [InlineData("S4", "S4_L1_001", "s4_delivery_cycle_metric", "/aidop/s4/delivery/supplier-shipment")]
  134. [InlineData("S4", "S4_L3_004", "s4_purchase_execution_metric", "/aidop/s4/execution-kanban/supplier-shortage-kanban")]
  135. [InlineData("S5", "S5_L1_001", "s5_material_online_cycle_metric", "/aidop/s5/inventory/inout-query")]
  136. [InlineData("S5", "S5_L1_002", "s5_material_online_fulfillment_metric", "/aidop/s5/warehouse/production-issue")]
  137. [InlineData("S5", "S5_L2_004", "s5_iqc_bill_metric", "/aidop/s5/iqc/result-list")]
  138. [InlineData("S6", "S6_L2_002", "s6_work_order_fulfillment_metric", "/aidop/s6/production-record/order-list")]
  139. [InlineData("S7", "S7_L1_001", "s7_shipment_cycle_metric", "/aidop/s7/finished-outbound/sales-shipment-notice")]
  140. [InlineData("S7", "S7_L1_002", "s7_shipment_fulfillment_metric", "/aidop/s7/finished-outbound/sales-shipment-notice")]
  141. [InlineData("S7", "S7_L2_002", "s7_fqc_result_metric", "/aidop/s7/fqc/result-list")]
  142. [InlineData("S9", "S9_L1_001", "s9_quality_return_txn_metric", "/aidop/s7/finished-outbound/sales-shipment-notice")]
  143. public void BoundMetric_ResolvesOnlyExplicitSource(string module, string metricCode, string sourceKey, string drillPath)
  144. {
  145. var sources = SmartDiagnosisEvidenceRegistry.ResolveMetric(module, metricCode);
  146. var source = Assert.Single(sources);
  147. Assert.Equal(sourceKey, source.Key);
  148. Assert.Equal(drillPath, source.DrillPath);
  149. Assert.Contains("@metricCode", source.CountSql, StringComparison.Ordinal);
  150. Assert.Contains("@metricCode", source.ItemSql, StringComparison.Ordinal);
  151. Assert.DoesNotContain(SmartDiagnosisEvidenceRegistry.Resolve(module), x => x.Key == sourceKey);
  152. }
  153. [Fact]
  154. public void S9_LeafMetric_DoesNotUseModuleUnion()
  155. {
  156. Assert.Empty(SmartDiagnosisEvidenceRegistry.ResolveMetric("S9", "S9_L1_002"));
  157. var bound = Assert.Single(SmartDiagnosisEvidenceRegistry.ResolveMetric("S9", "S9_L1_001"));
  158. Assert.Equal("s9_quality_return_txn_metric", bound.Key);
  159. Assert.Contains("销售退货", bound.ItemSql, StringComparison.Ordinal);
  160. Assert.DoesNotContain(SmartDiagnosisEvidenceRegistry.Resolve("S9"), x => x.MetricCodes.Count > 0);
  161. }
  162. [Fact]
  163. public void ClientCannotRegisterArbitraryTable()
  164. {
  165. Assert.Null(SmartDiagnosisEvidenceRegistry.Get("sys_user"));
  166. Assert.Null(SmartDiagnosisEvidenceRegistry.Get("ado_smart_ops_improvement_plan;drop table"));
  167. }
  168. }