TermRemoteCtl/apps/windows_agent/tests/TermRemoteCtl.Agent.Tests/Sessions/SessionRegistryTests.cs

139 lines
4.8 KiB
C#

using TermRemoteCtl.Agent.Sessions;
using Microsoft.Extensions.Options;
using TermRemoteCtl.Agent.Configuration;
using TermRemoteCtl.Agent.History;
namespace TermRemoteCtl.Agent.Tests.Sessions;
public class SessionRegistryTests
{
[Fact]
public void Create_Returns_Record_And_List_Is_Ordered_By_Name()
{
using var harness = SessionRegistryHarness.Create();
var registry = harness.Registry;
var now = new DateTimeOffset(2026, 03, 27, 03, 00, 00, TimeSpan.Zero);
var zebra = registry.Create("Zebra", now);
var alpha = registry.Create("Alpha", now.AddMinutes(1));
Assert.Equal("Zebra", zebra.Name);
Assert.Equal("Alpha", alpha.Name);
Assert.Equal(["Alpha", "Zebra"], registry.List().Select(record => record.Name).ToArray());
}
[Fact]
public void Create_Sets_Record_Metadata()
{
using var harness = SessionRegistryHarness.Create();
var registry = harness.Registry;
var now = new DateTimeOffset(2026, 03, 27, 03, 15, 00, TimeSpan.Zero);
var record = registry.Create("Shell", now);
Assert.False(string.IsNullOrWhiteSpace(record.SessionId));
Assert.Equal("Shell", record.Name);
Assert.Equal("created", record.Status);
Assert.Equal(now, record.CreatedAtUtc);
Assert.Equal(now, record.UpdatedAtUtc);
}
[Fact]
public async Task AppendOutputAsync_Stores_Recent_Scrollback_Lines()
{
using var harness = SessionRegistryHarness.Create(lineLimit: 3);
var registry = harness.Registry;
var session = registry.Create("Shell", DateTimeOffset.UtcNow);
await registry.AppendOutputAsync(session.SessionId, "one\ntwo\nthree\n", CancellationToken.None);
var history = registry.GetHistory(session.SessionId, 2);
Assert.Equal(["two", "three"], history.Lines);
Assert.True(history.HasMoreAbove);
}
[Fact]
public async Task AppendOutputAsync_Persists_History_To_Log_File()
{
using var harness = SessionRegistryHarness.Create();
var registry = harness.Registry;
var session = registry.Create("Shell", DateTimeOffset.UtcNow);
await registry.AppendOutputAsync(session.SessionId, "dir\r\n", CancellationToken.None);
var logPath = Path.Combine(harness.DataRoot, "sessions", $"{session.SessionId}.log");
var content = await File.ReadAllTextAsync(logPath);
Assert.Equal("dir\r\n", content);
}
[Fact]
public async Task AppendOutputAsync_Stores_Recent_Replay_Output()
{
using var harness = SessionRegistryHarness.Create();
var registry = harness.Registry;
var session = registry.Create("Shell", DateTimeOffset.UtcNow);
await registry.AppendOutputAsync(session.SessionId, "prompt> ", CancellationToken.None);
await registry.AppendOutputAsync(session.SessionId, "dir\r\n", CancellationToken.None);
var replay = registry.GetReplaySnapshot(session.SessionId);
Assert.Equal("prompt> dir\r\n", replay);
}
[Fact]
public async Task Delete_Removes_Session_Record_And_History_Log()
{
using var harness = SessionRegistryHarness.Create();
var registry = harness.Registry;
var session = registry.Create("Shell", DateTimeOffset.UtcNow);
await registry.AppendOutputAsync(session.SessionId, "dir\r\n", CancellationToken.None);
await registry.DeleteAsync(session.SessionId, CancellationToken.None);
Assert.Empty(registry.List());
Assert.False(registry.TryGet(session.SessionId, out _));
Assert.False(File.Exists(Path.Combine(harness.DataRoot, "sessions", $"{session.SessionId}.log")));
Assert.Throws<KeyNotFoundException>(() => registry.GetHistory(session.SessionId, 10));
}
private sealed class SessionRegistryHarness : IDisposable
{
private SessionRegistryHarness(string dataRoot, SessionRegistry registry)
{
DataRoot = dataRoot;
Registry = registry;
}
public string DataRoot { get; }
public SessionRegistry Registry { get; }
public static SessionRegistryHarness Create(int lineLimit = 4000)
{
var dataRoot = Path.Combine(Path.GetTempPath(), "TermRemoteCtl.Tests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(dataRoot);
var options = Options.Create(new AgentOptions
{
DataRoot = dataRoot,
RingBufferLineLimit = lineLimit,
});
var historyStore = new SessionHistoryStore(dataRoot);
var registry = new SessionRegistry(historyStore, options);
return new SessionRegistryHarness(dataRoot, registry);
}
public void Dispose()
{
if (Directory.Exists(DataRoot))
{
Directory.Delete(DataRoot, true);
}
}
}
}