应文浩wenhao.ying@xiaobao100.com bce2612b64 feat: 完善具体实现
2026-04-06 15:25:34 +08:00

156 lines
5.5 KiB
C#

using FluentAssertions;
using FreeCode.Tasks;
using Xunit;
using TaskStatus = FreeCode.Core.Enums.TaskStatus;
namespace FreeCode.Tests.Integration;
public sealed class TaskManagerTests
{
[Fact]
public async Task BackgroundTaskManager_ShellTask_CompletesLifecycle()
{
await using var sut = new BackgroundTaskManager();
var states = new List<TaskStatus>();
sut.TaskStateChanged += (_, args) => states.Add(args.NewStatus);
var processStartInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = "/bin/zsh",
Arguments = "-lc \"printf completed\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
var task = await sut.CreateShellTaskAsync("printf completed", processStartInfo);
await WaitUntilAsync(() => sut.GetTask(task.TaskId)?.Status is TaskStatus.Completed or TaskStatus.Failed, TimeSpan.FromSeconds(5));
var updated = sut.GetTask(task.TaskId);
updated.Should().NotBeNull();
updated!.Status.Should().Be(TaskStatus.Completed);
states.Should().Contain(TaskStatus.Running);
states.Should().Contain(TaskStatus.Completed);
(await sut.GetTaskOutputAsync(task.TaskId)).Should().Contain("completed");
}
[Fact]
public async Task ShellTask_CapturesStdout()
{
await using var sut = new BackgroundTaskManager();
var task = await sut.CreateShellTaskAsync("printf test output", CreateShellProcess("printf 'test output'"));
await WaitUntilAsync(() => sut.GetTask(task.TaskId)?.Status is TaskStatus.Completed or TaskStatus.Failed, TimeSpan.FromSeconds(5));
var shellTask = sut.GetTask(task.TaskId).Should().BeOfType<FreeCode.Core.Models.LocalShellTask>().Subject;
shellTask.Stdout.Should().Contain("test output");
}
[Fact]
public async Task ShellTask_CapturesStderr()
{
await using var sut = new BackgroundTaskManager();
var task = await sut.CreateShellTaskAsync("write stderr", CreateShellProcess("printf 'err' >&2"));
await WaitUntilAsync(() => sut.GetTask(task.TaskId)?.Status is TaskStatus.Completed or TaskStatus.Failed, TimeSpan.FromSeconds(5));
var shellTask = sut.GetTask(task.TaskId).Should().BeOfType<FreeCode.Core.Models.LocalShellTask>().Subject;
shellTask.Stderr.Should().Contain("err");
}
[Fact]
public async Task ShellTask_ExitCode_Captured()
{
await using var sut = new BackgroundTaskManager();
var task = await sut.CreateShellTaskAsync("exit 42", CreateShellProcess("exit 42"));
await WaitUntilAsync(() => sut.GetTask(task.TaskId)?.Status is TaskStatus.Completed or TaskStatus.Failed, TimeSpan.FromSeconds(5));
var shellTask = sut.GetTask(task.TaskId).Should().BeOfType<FreeCode.Core.Models.LocalShellTask>().Subject;
shellTask.ExitCode.Should().Be(42);
}
[Fact]
public async Task StopTask_StopsRunningTask()
{
await using var sut = new BackgroundTaskManager();
var task = await sut.CreateShellTaskAsync("sleep 10", CreateShellProcess("sleep 10"));
await WaitUntilAsync(() => sut.GetTask(task.TaskId)?.Status == TaskStatus.Running, TimeSpan.FromSeconds(5));
await sut.StopTaskAsync(task.TaskId);
await WaitUntilAsync(() => sut.GetTask(task.TaskId)?.Status == TaskStatus.Stopped, TimeSpan.FromSeconds(5));
sut.GetTask(task.TaskId).Should().NotBeNull();
sut.GetTask(task.TaskId)!.Status.Should().Be(TaskStatus.Stopped);
}
[Fact]
public async Task ListTasks_ReturnsAllTasks()
{
await using var sut = new BackgroundTaskManager();
var first = await sut.CreateShellTaskAsync("printf first", CreateShellProcess("printf first"));
var second = await sut.CreateShellTaskAsync("printf second", CreateShellProcess("printf second"));
await WaitUntilAsync(() => sut.ListTasks().Count >= 2, TimeSpan.FromSeconds(5));
sut.ListTasks().Select(task => task.TaskId).Should().Contain([first.TaskId, second.TaskId]);
}
[Fact]
public async Task GetTask_ReturnsTaskById()
{
await using var sut = new BackgroundTaskManager();
var task = await sut.CreateShellTaskAsync("printf lookup", CreateShellProcess("printf lookup"));
sut.GetTask(task.TaskId).Should().NotBeNull();
sut.GetTask(task.TaskId)!.TaskId.Should().Be(task.TaskId);
}
[Fact]
public async Task GetTask_UnknownId_ReturnsNull()
{
await using var sut = new BackgroundTaskManager();
await Task.CompletedTask;
sut.GetTask("missing-task").Should().BeNull();
}
private static System.Diagnostics.ProcessStartInfo CreateShellProcess(string command)
{
return new System.Diagnostics.ProcessStartInfo
{
FileName = "/bin/zsh",
Arguments = $"-lc \"{command}\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
}
private static async Task WaitUntilAsync(Func<bool> condition, TimeSpan timeout)
{
var deadline = DateTime.UtcNow + timeout;
while (DateTime.UtcNow < deadline)
{
if (condition())
{
return;
}
await Task.Delay(50);
}
throw new TimeoutException("Condition was not met before timeout.");
}
}