namespace BuildFlow.Architecture.Tests; using Xunit; /// /// 工作流持久化任务和 Host 调度边界的源码架构测试。 /// public class WorkflowJobArchitectureTests { [Fact] public void ProcessEngineShouldNotUseProcessLocalTimerTasks() { var source = ReadSource("src/modules/workflow/Application/Engine/ProcessEngine.cs"); Assert.DoesNotContain("Task.Run", source); Assert.DoesNotContain("timer:{", source); } [Fact] public void WorkflowTimerSchedulerShouldUseMediatorWithoutWorkflowInfrastructure() { var source = ReadSource( "src/BuildFlow.Host/Services/BackgroundServices/WorkflowTimerSchedulerService.cs"); Assert.Contains("IMediator", source); Assert.Contains("mediator.Send", source); Assert.Contains("ProcessDueWorkflowTimersCommand", source); Assert.DoesNotContain("WorkflowDbContext", source); Assert.DoesNotContain("ProcessEngine", source); } [Fact] public void ImportJobProcessorServiceShouldUseMediatorWithoutWorkflowInfrastructure() { var source = ReadSource( "src/BuildFlow.Host/Services/BackgroundServices/ImportJobProcessorService.cs"); Assert.Contains("IMediator", source); Assert.Contains("mediator.Send", source); Assert.Contains("ProcessAvailableImportJobsCommand", source); Assert.DoesNotContain("WorkflowDbContext", source); Assert.DoesNotContain("IImportJobProcessor", source); Assert.DoesNotContain("BuildFlowImportJobStatus", source); Assert.DoesNotContain(".Where(", source); } private static string ReadSource(string relativePath) { var path = Path.Combine( FindRepoRoot().FullName, relativePath.Replace('/', Path.DirectorySeparatorChar)); Assert.True(System.IO.File.Exists(path), $"待验证源码不存在:{relativePath}"); return System.IO.File.ReadAllText(path); } private static DirectoryInfo FindRepoRoot() { var current = new DirectoryInfo(AppContext.BaseDirectory); while (current is not null) { if (System.IO.File.Exists(Path.Combine(current.FullName, "BuildFlow.slnx"))) return current; current = current.Parent; } throw new InvalidOperationException("无法定位 BuildFlow.slnx,无法验证工作流任务架构边界。"); } }