| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- using Xunit;
- namespace Admin.NET.Plugin.AiDOP.Tests.S6.Manufacturing;
- /// <summary>
- /// S6 Phase 1A · 生产指令中台消费层契约测试(源码契约断言,无需活库)。
- /// 覆盖:STD 扩列 + specification enrich(Domain+ItemNum)、消费层强租户隔离、只读中台不直连源库、真分页、筛选。
- /// </summary>
- public class S6ProductionInstructionContractTests
- {
- private static string ReadS2Transform() => File.ReadAllText(FindFile(
- "server", "Plugins", "Admin.NET.Plugin.AiDOP", "Production", "S2MdpSyncTransformService.cs"));
- private static string ReadService() => File.ReadAllText(FindFile(
- "server", "Plugins", "Admin.NET.Plugin.AiDOP", "Manufacturing", "S6ProductionInstructionService.cs"));
- [Fact]
- public void Std_Schedule_HasNewNullableColumns()
- {
- var s2 = ReadS2Transform();
- Assert.Contains("specification VARCHAR(200) NULL", s2);
- Assert.Contains("lot_serial VARCHAR(100) NULL", s2);
- Assert.Contains("drawing_no VARCHAR(100) NULL", s2);
- Assert.Contains("project VARCHAR(200) NULL", s2);
- Assert.Contains("work_order_type VARCHAR(50) NULL", s2);
- Assert.Contains("labor_variance DECIMAL(18,6) NULL", s2);
- // 唯一键不变
- Assert.Contains("uk_std_work_order_schedule (tenant_id, work_order)", s2);
- }
- [Fact]
- public void Specification_EnrichedFromItemMaster_ByDomainAndItemNum_NotItemNumOnly()
- {
- var s2 = ReadS2Transform();
- // specification 来自 ItemMaster.Descr1
- Assert.Contains("im.Descr1", s2);
- Assert.Contains("FROM ItemMaster", s2);
- // 关联必须同时按 Domain + ItemNum(去重取一,实测同键 Descr1 无冲突)
- Assert.Contains("GROUP BY `Domain`, ItemNum", s2);
- Assert.Contains("im.`Domain` = JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.Domain'))", s2);
- Assert.Contains("im.ItemNum = JSON_UNQUOTE(JSON_EXTRACT(s.raw_data,'$.ItemNum'))", s2);
- // 新列进入 upsert
- Assert.Contains("specification=VALUES(specification)", s2);
- Assert.Contains("lot_serial=VALUES(lot_serial)", s2);
- }
- [Fact]
- public void EnvelopeSourcedColumns_MappedFromRawData()
- {
- var s2 = ReadS2Transform();
- Assert.Contains("JSON_EXTRACT(s.raw_data,'$.LotSerial')", s2);
- Assert.Contains("JSON_EXTRACT(s.raw_data,'$.Drawing')", s2);
- Assert.Contains("JSON_EXTRACT(s.raw_data,'$.Project')", s2);
- Assert.Contains("JSON_EXTRACT(s.raw_data,'$.WoTyped')", s2);
- Assert.Contains("JSON_EXTRACT(s.raw_data,'$.LbrVar')", s2);
- }
- [Fact]
- public void Consumer_UsesStrictTenantScope_OnEverySql()
- {
- var svc = ReadService();
- Assert.Contains("AidopTenantScope.ResolveOrThrow", svc);
- Assert.Contains("m.tenant_id = @TenantId", svc);
- // COUNT / PAGE / DETAIL 都带租户过滤:至少出现 2 处显式 tenant 谓词(page where + detail where)
- var occurrences = svc.Split("m.tenant_id = @TenantId").Length - 1;
- Assert.True(occurrences >= 2, $"expected tenant predicate on page+detail, found {occurrences}");
- }
- [Fact]
- public void Consumer_ReadsMdpStdOnly_NeverSourceTables()
- {
- var svc = ReadService();
- Assert.Contains("FROM mdp_std_work_order_schedule", svc);
- Assert.DoesNotContain("WorkOrdMaster", svc);
- Assert.DoesNotContain("ItemMaster", svc);
- Assert.DoesNotContain("mes_morder", svc);
- }
- [Fact]
- public void Consumer_HasNoTenantFallback_AndNoSelectStar()
- {
- var svc = ReadService();
- Assert.DoesNotContain("tenant_id IS NULL", svc);
- Assert.DoesNotContain("tenant_id = 0", svc);
- Assert.DoesNotContain("SELECT *", svc);
- // 不硬编码工厂
- Assert.DoesNotContain("factory_id = 1", svc);
- Assert.DoesNotContain("factory_id = 8010", svc);
- }
- [Fact]
- public void Consumer_TruePagination_AndFilters()
- {
- var svc = ReadService();
- Assert.Contains("LIMIT {pageSize} OFFSET {offset}", svc);
- Assert.Contains("SELECT COUNT(1) FROM mdp_std_work_order_schedule", svc);
- Assert.Contains("m.work_order LIKE @WorkOrderNo", svc);
- Assert.Contains("m.lot_serial LIKE @LotSerial", svc);
- Assert.Contains("m.item_code LIKE @ItemCode", svc);
- Assert.Contains("m.status = @Status", svc);
- Assert.Contains("m.order_date >= @OrderDateStart", svc);
- Assert.Contains("DATE_ADD(@OrderDateEnd, INTERVAL 1 DAY)", svc);
- Assert.Contains("ORDER BY m.order_date DESC, m.work_order DESC", svc);
- }
- private static string FindFile(params string[] parts)
- {
- var dir = new DirectoryInfo(AppContext.BaseDirectory);
- while (dir != null)
- {
- var candidate = Path.Combine(new[] { dir.FullName }.Concat(parts).ToArray());
- if (File.Exists(candidate)) return candidate;
- dir = dir.Parent;
- }
- throw new FileNotFoundException(string.Join("/", parts));
- }
- }
|