diff --git a/src/Docker.DotNet/Endpoints/ExecOperations.cs b/src/Docker.DotNet/Endpoints/ExecOperations.cs index 221ff6e2..55d5e854 100644 --- a/src/Docker.DotNet/Endpoints/ExecOperations.cs +++ b/src/Docker.DotNet/Endpoints/ExecOperations.cs @@ -60,4 +60,20 @@ public async Task StartContainerExecAsync(string id, Containe return new MultiplexedStream(response, !parameters.TTY); } + + public Task ResizeExecTtyAsync(string id, ContainerResizeParameters parameters, CancellationToken cancellationToken = default) + { + if (string.IsNullOrEmpty(id)) + { + throw new ArgumentNullException(nameof(id)); + } + + if (parameters == null) + { + throw new ArgumentNullException(nameof(parameters)); + } + + var queryParameters = new QueryString(parameters); + return _client.MakeRequestAsync([NoSuchContainerHandler], HttpMethod.Post, $"exec/{id}/resize", queryParameters, cancellationToken); + } } \ No newline at end of file diff --git a/src/Docker.DotNet/Endpoints/IExecOperations.cs b/src/Docker.DotNet/Endpoints/IExecOperations.cs index db9824a6..dc747757 100644 --- a/src/Docker.DotNet/Endpoints/IExecOperations.cs +++ b/src/Docker.DotNet/Endpoints/IExecOperations.cs @@ -7,4 +7,6 @@ public interface IExecOperations Task CreateContainerExecAsync(string id, ContainerExecCreateParameters parameters, CancellationToken cancellationToken = default); Task StartContainerExecAsync(string id, ContainerExecStartParameters parameters, CancellationToken cancellationToken = default); + + Task ResizeExecTtyAsync(string id, ContainerResizeParameters parameters, CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/test/Docker.DotNet.Tests/IExecOperationsTests.cs b/test/Docker.DotNet.Tests/IExecOperationsTests.cs new file mode 100644 index 00000000..f2da1f12 --- /dev/null +++ b/test/Docker.DotNet.Tests/IExecOperationsTests.cs @@ -0,0 +1,93 @@ +namespace Docker.DotNet.Tests; + +[Collection(nameof(TestCollection))] +public class IExecOperationsTests +{ + private readonly TestFixture _testFixture; + private readonly ITestOutputHelper _testOutputHelper; + + public IExecOperationsTests(TestFixture testFixture, ITestOutputHelper testOutputHelper) + { + _testFixture = testFixture; + _testOutputHelper = testOutputHelper; + } + + [Fact] + public async Task ResizeExecTtyAsync_RunningExec_Succeeds() + { + // Given: a running container with a TTY exec session + var createContainerResponse = await _testFixture.DockerClient.Containers.CreateContainerAsync( + new CreateContainerParameters + { + Image = _testFixture.Image.ID, + Entrypoint = CommonCommands.SleepInfinity + }, + _testFixture.Cts.Token + ); + + await _testFixture.DockerClient.Containers.StartContainerAsync( + createContainerResponse.ID, + new ContainerStartParameters(), + _testFixture.Cts.Token + ); + + var execCreateResponse = await _testFixture.DockerClient.Exec.CreateContainerExecAsync( + createContainerResponse.ID, + new ContainerExecCreateParameters + { + AttachStdout = true, + AttachStderr = true, + AttachStdin = true, + TTY = true, + Cmd = ["/bin/sh"] + }, + _testFixture.Cts.Token + ); + + // Start the exec to make it running (resize only works on a running exec) + using var stream = await _testFixture.DockerClient.Exec.StartContainerExecAsync( + execCreateResponse.ID, + new ContainerExecStartParameters { TTY = true }, + _testFixture.Cts.Token + ); + + // When: resize the exec TTY + await _testFixture.DockerClient.Exec.ResizeExecTtyAsync( + execCreateResponse.ID, + new ContainerResizeParameters + { + Height = 40, + Width = 120 + }, + _testFixture.Cts.Token + ); + + // Then: no exception means success + _testOutputHelper.WriteLine("ResizeExecTtyAsync succeeded for running exec session."); + + // Verify exec is still running + var execInspect = await _testFixture.DockerClient.Exec.InspectContainerExecAsync( + execCreateResponse.ID, + _testFixture.Cts.Token + ); + + Assert.True(execInspect.Running); + } + + [Fact] + public async Task ResizeExecTtyAsync_NonExistentExecId_ThrowsException() + { + // When/Then: resizing a non-existent exec ID should throw + await Assert.ThrowsAsync( + () => _testFixture.DockerClient.Exec.ResizeExecTtyAsync( + Guid.NewGuid().ToString("N"), + new ContainerResizeParameters + { + Height = 24, + Width = 80 + }, + _testFixture.Cts.Token + ) + ); + } +}