Использую
Nuke
В проекте есть e2e тесты, которые должны выполняться, когда запущена апишка.
Сейчас я делаю так:
Target на сборку проектов
Target на запуск, который зависит от сборки и триггерит остановку. Тут я делаю Process.Start, перенаправляю stdout и прочее. Запущенные процессы складываю в List
Target на тесты, который зависит от запуска и выполняется строго до остановки
Target на остановку. Тут я прохожусь по всем процессам, останавливаю их, и делаю Dispose всех открытых файлов и StreamWriter-ов
Мне кажется, что получилось немного запутанно, но ничего лучше не придумал.
Вопрос: можно ли это всё сделать красивее? Как подобное делаете вы?
class Build {
Target FunctionalTests => _ => _
.After(IntegrationTests)
.DependsOn(StartForFTests)
.DependsOn(Compile)
.Executes(() =>
{
foreach (var project in Solution.AllProjects.Where(x => x.Name.EndsWith("Tests.Functional")))
{
Logger.Info("Starting {0}", project.Name);
DotNetTest(c => c
.SetProjectFile(project.Path)
.EnableNoBuild());
}
});
#region FTests flow
readonly List<Process> Processes = new();
readonly List<IDisposable> Resources = new();
readonly List<Task> Tasks = new();
Target StartForFTests => _ => _
.Unlisted()
.DependsOn(Publish)
.Executes(async () =>
{
foreach (var exec in Out.GlobFiles("*/*.exe"))
{
var processStartInfo = new ProcessStartInfo
{
FileName = exec,
RedirectStandardOutput = true,
RedirectStandardError = true
};
Logger.Info("Starting {0}", processStartInfo.FileName);
var process = Process.Start(processStartInfo);
if (process != null)
{
Logger.Success("Process {0} started", process.ProcessName);
Processes.Add(process);
}
else
{
Logger.Error("Can't start {0}", processStartInfo.FileName);
}
}
if (!Directory.Exists(Logs))
Directory.CreateDirectory(Logs);
foreach (var proc in Processes)
{
var file = File.Open(Logs / proc.ProcessName + ".log", FileMode.OpenOrCreate);
var errFile = File.Open(Logs / proc.ProcessName + ".error.log", FileMode.OpenOrCreate);
Resources.Add(file);
Resources.Add(errFile);
Tasks.Add(proc.StandardOutput.BaseStream.CopyToAsync(file));
Tasks.Add(proc.StandardError.BaseStream.CopyToAsync(errFile));
}
Logger.Info("Warmup");
await Task.Delay(TimeSpan.FromSeconds(15));
var succ = true;
foreach (var proc in Processes.Where(proc => proc.HasExited))
{
Logger.Error("{0} has exited", proc.ProcessName);
succ = false;
}
if (succ)
Logger.Success("All processes started");
ControlFlow.Fail("Some processes exited");
});
Target StopAfterFTests => _ => _
.Unlisted()
.TriggeredBy(StartForFTests)
.After(FunctionalTests)
.AssuredAfterFailure()
.Executes(async () =>
{
foreach (var process in Processes) process.Kill();
foreach (var process in Processes) process.WaitForExit();
await Task.WhenAll(Tasks);
Tasks.Clear();
Processes.Clear();
foreach (var resource in Resources) resource.Dispose();
Resources.Clear();
});
#endregion
}