using System.Text.RegularExpressions; using Xunit; namespace Admin.NET.Plugin.AiDOP.Tests.DataPlatform; public class T8KpiTenantIsolationContractTests { [Theory] [InlineData("MaterialWarehouse", "S5MdpSyncTransformService.cs", 6)] [InlineData("FinishedWarehouse", "S7MdpSyncTransformService.cs", 4)] public void StandardLayerQueries_FilterByTenantAndZtid( string moduleDirectory, string serviceFile, int expectedQueryCount) { var source = ReadServiceSource(moduleDirectory, serviceFile); var queries = ExtractStandardLayerQueries(source); Assert.Equal(expectedQueryCount, queries.Count); foreach (var query in queries) { Assert.Contains("@tenantId", query, StringComparison.OrdinalIgnoreCase); Assert.Contains("@ztid", query, StringComparison.OrdinalIgnoreCase); var aliases = Regex.Matches( query, @"(?:from|join)\s+mdp_std_t8_\w+\s+(?[a-z])\b", RegexOptions.IgnoreCase) .Select(match => match.Groups["alias"].Value) .Distinct(StringComparer.OrdinalIgnoreCase); foreach (var alias in aliases) { Assert.Matches( new Regex($@"\b{Regex.Escape(alias)}\.tenant_id\b", RegexOptions.IgnoreCase), query); } } Assert.Contains( "new SugarParameter(\"@tenantId\", option.TargetTenantId)", source, StringComparison.Ordinal); } [Fact] public void S5_FulfillmentAndEfficiency_KeepEveryJoinedTableInTargetTenant() { var source = ReadServiceSource("MaterialWarehouse", "S5MdpSyncTransformService.cs"); Assert.Contains("l.tenant_id=h.tenant_id", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("where tenant_id=@tenantId and ztid=@ztid", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("h.tenant_id=@tenantId and h.ztid=@ztid", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("b.tenant_id=a.tenant_id", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("where tenant_id=@tenantId and ztid=@ztid and zzzt='在职'", source, StringComparison.OrdinalIgnoreCase); } [Fact] public void S7_CycleFulfillmentAndEfficiency_KeepEveryJoinedTableInTargetTenant() { var source = ReadServiceSource("FinishedWarehouse", "S7MdpSyncTransformService.cs"); Assert.Contains("b.tenant_id=a.tenant_id", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("d.tenant_id=a.tenant_id", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("c.tenant_id=a.tenant_id", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("a.tenant_id=@tenantId and a.ztid=@ztid", source, StringComparison.OrdinalIgnoreCase); Assert.Contains("where tenant_id=@tenantId and ztid=@ztid and zzzt='在职'", source, StringComparison.OrdinalIgnoreCase); } private static List ExtractStandardLayerQueries(string source) => Regex.Matches( source, @"const string \w+\s*=\s*@""(?[\s\S]*?)"";", RegexOptions.CultureInvariant) .Select(match => match.Groups["sql"].Value) .Where(sql => sql.Contains("mdp_std_t8_", StringComparison.OrdinalIgnoreCase)) .ToList(); private static string ReadServiceSource(string moduleDirectory, string serviceFile) { var dir = new DirectoryInfo(AppContext.BaseDirectory); while (dir != null) { var candidate = Path.Combine( dir.FullName, "server", "Plugins", "Admin.NET.Plugin.AiDOP", moduleDirectory, serviceFile); if (File.Exists(candidate)) return File.ReadAllText(candidate); dir = dir.Parent; } throw new FileNotFoundException(serviceFile); } }