147 lines
4.7 KiB
C#
147 lines
4.7 KiB
C#
using Microsoft.Extensions.Options;
|
|
using TermRemoteCtl.Agent.Configuration;
|
|
using TermRemoteCtl.Agent.History;
|
|
using TermRemoteCtl.Agent.Sessions;
|
|
using TermRemoteCtl.Agent.Terminal;
|
|
|
|
namespace TermRemoteCtl.Agent.Tests.Terminal;
|
|
|
|
public class PowerShellSessionHostTests
|
|
{
|
|
[Fact]
|
|
public async Task ResizeAsync_Forwards_To_ConPty_Session()
|
|
{
|
|
var factory = new FakeConPtySessionFactory();
|
|
using var harness = HostHarness.Create(factory);
|
|
await using var host = harness.Host;
|
|
|
|
var session = harness.Registry.Create("alpha", DateTimeOffset.UtcNow);
|
|
|
|
await host.StartAsync(session.SessionId, CancellationToken.None);
|
|
await host.ResizeAsync(session.SessionId, 120, 40, CancellationToken.None);
|
|
|
|
Assert.Equal((120, 40), factory.Session.ResizeCalls.Single());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task StartAsync_Forwards_WorkingDirectory_To_SessionFactory()
|
|
{
|
|
var factory = new FakeConPtySessionFactory();
|
|
using var harness = HostHarness.Create(factory);
|
|
await using var host = harness.Host;
|
|
var session = harness.Registry.Create(
|
|
"alpha",
|
|
DateTimeOffset.UtcNow,
|
|
workingDirectory: @"C:\repo\termremotectl");
|
|
|
|
await host.StartAsync(session.SessionId, CancellationToken.None);
|
|
|
|
Assert.Equal(@"C:\repo\termremotectl", factory.LastWorkingDirectory);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Session_Output_Is_Captured_In_Registry_History()
|
|
{
|
|
var factory = new FakeConPtySessionFactory();
|
|
using var harness = HostHarness.Create(factory, lineLimit: 3);
|
|
var session = harness.Registry.Create("Shell", DateTimeOffset.UtcNow);
|
|
await using var host = harness.Host;
|
|
|
|
await host.StartAsync(session.SessionId, CancellationToken.None);
|
|
factory.Session.EmitOutput(session.SessionId, "one\ntwo\nthree\n");
|
|
|
|
var history = harness.Registry.GetHistory(session.SessionId, 2);
|
|
|
|
Assert.Equal(["two", "three"], history.Lines);
|
|
Assert.True(history.HasMoreAbove);
|
|
}
|
|
|
|
private sealed class HostHarness : IDisposable
|
|
{
|
|
private HostHarness(string dataRoot, SessionRegistry registry, PowerShellSessionHost host)
|
|
{
|
|
DataRoot = dataRoot;
|
|
Registry = registry;
|
|
Host = host;
|
|
}
|
|
|
|
public string DataRoot { get; }
|
|
|
|
public SessionRegistry Registry { get; }
|
|
|
|
public PowerShellSessionHost Host { get; }
|
|
|
|
public static HostHarness Create(FakeConPtySessionFactory factory, 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 registry = new SessionRegistry(new SessionHistoryStore(dataRoot), options);
|
|
var host = new PowerShellSessionHost(factory, registry);
|
|
|
|
return new HostHarness(dataRoot, registry, host);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (Directory.Exists(DataRoot))
|
|
{
|
|
Directory.Delete(DataRoot, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
private sealed class FakeConPtySessionFactory : IConPtySessionFactory
|
|
{
|
|
public FakeConPtySession Session { get; } = new();
|
|
public string? LastWorkingDirectory { get; private set; }
|
|
|
|
public IConPtySession Create(string sessionId, string? workingDirectory = null)
|
|
{
|
|
Session.SessionId = sessionId;
|
|
LastWorkingDirectory = workingDirectory;
|
|
return Session;
|
|
}
|
|
}
|
|
|
|
private sealed class FakeConPtySession : IConPtySession
|
|
{
|
|
public string SessionId { get; set; } = string.Empty;
|
|
|
|
public event EventHandler<TerminalOutputEventArgs>? OutputReceived;
|
|
|
|
public List<(int Columns, int Rows)> ResizeCalls { get; } = new();
|
|
|
|
public Task StartAsync(CancellationToken cancellationToken)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task WriteInputAsync(string input, CancellationToken cancellationToken)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task ResizeAsync(int columns, int rows, CancellationToken cancellationToken)
|
|
{
|
|
ResizeCalls.Add((columns, rows));
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public void EmitOutput(string sessionId, string chunk)
|
|
{
|
|
OutputReceived?.Invoke(this, new TerminalOutputEventArgs(sessionId, chunk));
|
|
}
|
|
|
|
public ValueTask DisposeAsync()
|
|
{
|
|
return ValueTask.CompletedTask;
|
|
}
|
|
}
|
|
}
|