Fix terminal reconnect output pump lifetime
This commit is contained in:
parent
f2282b8619
commit
4fcbb07fdc
@ -22,6 +22,7 @@ internal sealed class HelperBackedConPtySession : IConPtySession
|
||||
private StreamWriter? _commandWriter;
|
||||
private StreamReader? _outputReader;
|
||||
private Task? _outputPumpTask;
|
||||
private readonly CancellationTokenSource _lifetime = new();
|
||||
private bool _started;
|
||||
private bool _disposed;
|
||||
|
||||
@ -104,7 +105,7 @@ internal sealed class HelperBackedConPtySession : IConPtySession
|
||||
throw new InvalidOperationException($"Unexpected ConPTY helper startup handshake: {handshake}");
|
||||
}
|
||||
|
||||
_outputPumpTask = Task.Run(() => PumpOutputAsync(_outputReader, cancellationToken), cancellationToken);
|
||||
_outputPumpTask = Task.Run(() => PumpOutputAsync(_outputReader, _lifetime.Token), CancellationToken.None);
|
||||
_started = true;
|
||||
}
|
||||
|
||||
@ -149,6 +150,7 @@ internal sealed class HelperBackedConPtySession : IConPtySession
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
_lifetime.Cancel();
|
||||
|
||||
if (_commandWriter is not null)
|
||||
{
|
||||
@ -182,6 +184,7 @@ internal sealed class HelperBackedConPtySession : IConPtySession
|
||||
_commandPipe?.Dispose();
|
||||
_outputPipe?.Dispose();
|
||||
_helperProcess?.Dispose();
|
||||
_lifetime.Dispose();
|
||||
}
|
||||
|
||||
private async Task PumpOutputAsync(StreamReader reader, CancellationToken cancellationToken)
|
||||
|
||||
@ -44,6 +44,46 @@ public sealed class TerminalSmokeCheckTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuiltAgentExe_Reconnects_Existing_Terminal_And_Accepts_Input()
|
||||
{
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await using var fixture = new BuiltAgentFixture();
|
||||
await fixture.StartAsync();
|
||||
|
||||
try
|
||||
{
|
||||
var session = await fixture.CreateSessionAsync("smoke-reconnect");
|
||||
|
||||
using (var firstSocket = await fixture.ConnectTerminalAsync(session.SessionId))
|
||||
{
|
||||
_ = await fixture.ReceiveTextAsync(firstSocket, TimeSpan.FromSeconds(20));
|
||||
await fixture.SendTextAsync(firstSocket, JsonSerializer.Serialize(new { type = "input", input = "Write-Output first\r" }));
|
||||
_ = await fixture.ReceiveTextContainingAsync(firstSocket, "first", TimeSpan.FromSeconds(20));
|
||||
}
|
||||
|
||||
using var secondSocket = await fixture.ConnectTerminalAsync(session.SessionId);
|
||||
var attached = await fixture.ReceiveTextAsync(secondSocket, TimeSpan.FromSeconds(20));
|
||||
var attachedPayload = JsonSerializer.Deserialize<TerminalAttachResponse>(attached, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
||||
Assert.NotNull(attachedPayload);
|
||||
Assert.Equal("attached", attachedPayload!.Type);
|
||||
Assert.Equal(session.SessionId, attachedPayload.SessionId);
|
||||
|
||||
await fixture.SendTextAsync(secondSocket, JsonSerializer.Serialize(new { type = "input", input = "Write-Output second\r" }));
|
||||
var output = await fixture.ReceiveTextContainingAsync(secondSocket, "second", TimeSpan.FromSeconds(20));
|
||||
|
||||
Assert.Contains("second", output, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"{ex.Message}{Environment.NewLine}{fixture.GetDiagnostics()}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class BuiltAgentFixture : IAsyncDisposable
|
||||
{
|
||||
private readonly string _projectRoot;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user