| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- using Admin.NET.Plugin.AiDOP.Controllers;
- using Admin.NET.Plugin.AiDOP.Entity;
- using Xunit;
- namespace Admin.NET.Plugin.AiDOP.Tests.SmartOps;
- public class SmartDiagnosisTreeTests
- {
- [Fact]
- public void SpecifiedRoot_WithL2_ReturnsOnlyOwnChildren()
- {
- var kpis = SampleTree();
- var values = new Dictionary<string, SmartDiagnosisTree.ValueSnap>(StringComparer.OrdinalIgnoreCase);
- var resolved = SmartDiagnosisTree.ResolveRoot(L1(kpis), values, "S1_L1_001");
- Assert.Null(resolved.Error);
- Assert.Equal(SmartDiagnosisTree.SelectionSpecified, resolved.SelectionMode);
- Assert.Equal("S1_L1_001", resolved.Root!.MetricCode);
- var children = SmartDiagnosisTree.DirectChildren(kpis, resolved.Root.Id, 2);
- Assert.Equal(new[] { "S1_L2_001", "S1_L2_004" }, children.Select(x => x.MetricCode).ToArray());
- Assert.DoesNotContain(children, x => x.MetricCode == "S1_L2_002");
- }
- [Fact]
- public void SpecifiedRoot_WithoutL2_ReturnsEmptyChildren()
- {
- var kpis = SampleTree();
- var resolved = SmartDiagnosisTree.ResolveRoot(L1(kpis), EmptyValues(), "S1_L1_004");
- Assert.Null(resolved.Error);
- Assert.Equal("S1_L1_004", resolved.Root!.MetricCode);
- Assert.Empty(SmartDiagnosisTree.DirectChildren(kpis, resolved.Root.Id, 2));
- }
- [Fact]
- public void GlobalWorst_WithoutL2_StillSelectsThatRoot()
- {
- var kpis = SampleTree();
- var values = new Dictionary<string, SmartDiagnosisTree.ValueSnap>(StringComparer.OrdinalIgnoreCase)
- {
- ["S1_L1_001"] = new(20m, 20m),
- ["S1_L1_002"] = new(90m, 95m),
- ["S1_L1_004"] = new(101.94m, 15m),
- };
- var resolved = SmartDiagnosisTree.ResolveRoot(L1(kpis), values, null);
- Assert.Null(resolved.Error);
- Assert.Equal(SmartDiagnosisTree.SelectionGlobalWorst, resolved.SelectionMode);
- Assert.Equal("S1_L1_004", resolved.Root!.MetricCode);
- Assert.Empty(SmartDiagnosisTree.DirectChildren(kpis, resolved.Root.Id, 2));
- }
- [Fact]
- public void MixedL3_OnlyConfiguredChildrenReturned()
- {
- var kpis = SampleTree();
- var l2WithL3 = kpis.First(x => x.MetricCode == "S1_L2_001");
- var l2WithoutL3 = kpis.First(x => x.MetricCode == "S1_L2_004");
- var withL3 = SmartDiagnosisTree.DirectChildren(kpis, l2WithL3.Id, 3);
- var withoutL3 = SmartDiagnosisTree.DirectChildren(kpis, l2WithoutL3.Id, 3);
- Assert.Single(withL3);
- Assert.Equal("S1_L3_001", withL3[0].MetricCode);
- Assert.Empty(withoutL3);
- }
- [Fact]
- public void L3WithoutL4_ReturnsEmptyLeaf()
- {
- var kpis = SampleTree();
- var l3 = kpis.First(x => x.MetricCode == "S1_L3_001");
- Assert.Empty(SmartDiagnosisTree.DirectChildren(kpis, l3.Id, 4));
- }
- [Fact]
- public void InvalidSpecifiedMetric_DoesNotFallBackToGlobal()
- {
- var kpis = SampleTree();
- var values = new Dictionary<string, SmartDiagnosisTree.ValueSnap>(StringComparer.OrdinalIgnoreCase)
- {
- ["S1_L1_004"] = new(101.94m, 15m),
- };
- var resolved = SmartDiagnosisTree.ResolveRoot(L1(kpis), values, "NOT_AN_L1");
- Assert.Null(resolved.Root);
- Assert.Equal(SmartDiagnosisTree.SelectionSpecified, resolved.SelectionMode);
- Assert.Equal("metricCode 不是当前模块已启用的 L1 指标。", resolved.Error);
- }
- [Fact]
- public void BuildDiagnosisRate_UsesFormula_NotHardcoded58()
- {
- Assert.Equal("84%", SmartDiagnosisTree.BuildDiagnosisRate(1.79m, 1.5m, "lower_is_better"));
- Assert.Equal("50%", SmartDiagnosisTree.BuildDiagnosisRate(50m, 100m, "higher_is_better"));
- Assert.Equal("-", SmartDiagnosisTree.BuildDiagnosisRate(null, 1.5m, "lower_is_better"));
- Assert.Equal("-", SmartDiagnosisTree.BuildDiagnosisRate(1.79m, 0m, "lower_is_better"));
- }
- private static List<AdoSmartOpsKpiMaster> L1(List<AdoSmartOpsKpiMaster> kpis) =>
- kpis.Where(x => x.MetricLevel == 1).OrderBy(x => x.SortNo).ToList();
- private static Dictionary<string, SmartDiagnosisTree.ValueSnap> EmptyValues() =>
- new(StringComparer.OrdinalIgnoreCase);
- private static List<AdoSmartOpsKpiMaster> SampleTree()
- {
- var l1Cycle = Kpi(337, "S1_L1_001", "订单评审周期(天)", 1, null, 1, "lower_is_better");
- var l1Rate = Kpi(338, "S1_L1_002", "订单评审满足率(%)", 1, null, 2, "higher_is_better");
- var l1Turn = Kpi(340, "S1_L1_004", "成品库存周转(天)", 1, null, 4, "lower_is_better");
- var l2Contract = Kpi(369, "S1_L2_001", "合同评审周期(天)", 2, l1Cycle.Id, 1, "lower_is_better");
- var l2Rate = Kpi(370, "S1_L2_002", "合同评审满足率(%)", 2, l1Rate.Id, 2, "higher_is_better");
- var l2Bom = Kpi(372, "S1_L2_004", "BOM评审周期(天)", 2, l1Cycle.Id, 4, "lower_is_better");
- var l3 = Kpi(401, "S1_L3_001", "意见评审", 3, l2Contract.Id, 1, "lower_is_better");
- return [l1Cycle, l1Rate, l1Turn, l2Contract, l2Rate, l2Bom, l3];
- }
- private static AdoSmartOpsKpiMaster Kpi(
- long id, string code, string name, int level, long? parentId, int sortNo, string direction) =>
- new()
- {
- Id = id,
- MetricCode = code,
- MetricName = name,
- MetricLevel = level,
- ParentId = parentId,
- SortNo = sortNo,
- Direction = direction,
- ModuleCode = "S1",
- IsEnabled = true,
- };
- }
|