namespace BuildFlow.Architecture.Tests; using Xunit; /// /// BuildFlow 低代码按钮权限架构约束。按钮运行时需要查 platform 权限时, /// 必须通过目标模块 CQRS Query 调用,不能在 Host 注册 in-process service bridge。 /// public class BuildFlowButtonCqrsArchitectureTests { [Fact] public void BuildFlowButtonPermissionShouldNotUseHostServiceBridge() { var repoRoot = FindRepoRoot(); var sourceFiles = Directory .EnumerateFiles(Path.Combine(repoRoot.FullName, "src"), "*.cs", SearchOption.AllDirectories) .Where(path => !ContainsPathSegment(path, "bin") && !ContainsPathSegment(path, "obj")) .Select(path => new { RelativePath = Path.GetRelativePath(repoRoot.FullName, path).Replace('\\', '/'), Text = File.ReadAllText(path), }) .Where(file => file.Text.Contains("IBuildFlowButtonPermissionChecker", StringComparison.Ordinal) || file.Text.Contains("InProcessBuildFlowButtonPermissionChecker", StringComparison.Ordinal)) .Select(file => file.RelativePath) .Order(StringComparer.Ordinal) .ToArray(); Assert.True( sourceFiles.Length == 0, "BuildFlow 按钮权限不能通过 Host service/interface bridge 串联 platform;请在 workflow 命令处理链路中通过 IMediator 发送 platform Query。当前残留:" + Environment.NewLine + string.Join(Environment.NewLine, sourceFiles)); } private static DirectoryInfo FindRepoRoot() { var current = new DirectoryInfo(AppContext.BaseDirectory); while (current is not null) { if (File.Exists(Path.Combine(current.FullName, "BuildFlow.slnx"))) { return current; } current = current.Parent; } throw new InvalidOperationException("无法定位 BuildFlow.slnx,架构测试无法确定仓库边界。"); } private static bool ContainsPathSegment(string path, string segment) { return path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) .Any(part => string.Equals(part, segment, StringComparison.Ordinal)); } }