From 30309be86bc1695e8e8ad6f39bb1a50b63d8ec20 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Mon, 9 Oct 2023 22:03:12 +0200 Subject: [PATCH 1/4] feat: Use Docker's inspect API to get resource information --- .../Builders/ContainerBuilder`3.cs | 2 +- .../Builders/IContainerBuilder`2.cs | 2 +- .../Builders/IImageFromDockerfileBuilder`1.cs | 2 +- .../Builders/ImageFromDockerfileBuilder.cs | 2 +- .../Clients/DockerContainerOperations.cs | 26 +++++++++---------- .../Clients/DockerImageOperations.cs | 25 ++++++++++-------- .../Clients/DockerNetworkOperations.cs | 21 ++++++++------- .../Clients/DockerVolumeOperations.cs | 22 +++++++++++----- .../Clients/IDockerContainerOperations.cs | 4 +-- .../Clients/IDockerImageOperations.cs | 2 +- .../Clients/IDockerNetworkOperations.cs | 2 +- .../Clients/IDockerVolumeOperations.cs | 2 +- .../Clients/IHasListOperations.cs | 12 +++++---- .../Clients/ITestcontainersClient.cs | 8 ------ .../Clients/TestcontainersClient.cs | 6 ----- .../Containers/ContainerConfiguration.cs | 4 +-- .../Containers/IContainerConfiguration.cs | 2 +- .../IImageFromDockerfileConfiguration.cs | 2 +- .../ImageFromDockerfileConfiguration.cs | 4 +-- .../Containers/DockerContainer.cs | 8 +++--- .../Images/FutureDockerImage.cs | 4 +-- src/Testcontainers/Images/PullPolicy.cs | 6 ++--- src/Testcontainers/Volumes/DockerVolume.cs | 4 +-- 23 files changed, 85 insertions(+), 87 deletions(-) diff --git a/src/Testcontainers/Builders/ContainerBuilder`3.cs b/src/Testcontainers/Builders/ContainerBuilder`3.cs index b784d2eef..6df73eb1f 100644 --- a/src/Testcontainers/Builders/ContainerBuilder`3.cs +++ b/src/Testcontainers/Builders/ContainerBuilder`3.cs @@ -84,7 +84,7 @@ public TBuilderEntity WithImage(IImage image) } /// - public TBuilderEntity WithImagePullPolicy(Func imagePullPolicy) + public TBuilderEntity WithImagePullPolicy(Func imagePullPolicy) { return Clone(new ContainerConfiguration(imagePullPolicy: imagePullPolicy)); } diff --git a/src/Testcontainers/Builders/IContainerBuilder`2.cs b/src/Testcontainers/Builders/IContainerBuilder`2.cs index 2828ff61d..6516c3c22 100644 --- a/src/Testcontainers/Builders/IContainerBuilder`2.cs +++ b/src/Testcontainers/Builders/IContainerBuilder`2.cs @@ -78,7 +78,7 @@ public interface IContainerBuilder : I /// The image pull policy. /// A configured instance of . [PublicAPI] - TBuilderEntity WithImagePullPolicy(Func imagePullPolicy); + TBuilderEntity WithImagePullPolicy(Func imagePullPolicy); /// /// Sets the name. diff --git a/src/Testcontainers/Builders/IImageFromDockerfileBuilder`1.cs b/src/Testcontainers/Builders/IImageFromDockerfileBuilder`1.cs index a806707d6..47f2d7131 100644 --- a/src/Testcontainers/Builders/IImageFromDockerfileBuilder`1.cs +++ b/src/Testcontainers/Builders/IImageFromDockerfileBuilder`1.cs @@ -59,7 +59,7 @@ public interface IImageFromDockerfileBuilder /// The image build policy. /// A configured instance of . [PublicAPI] - TBuilderEntity WithImageBuildPolicy(Func imageBuildPolicy); + TBuilderEntity WithImageBuildPolicy(Func imageBuildPolicy); /// /// Removes an existing image before building it again. diff --git a/src/Testcontainers/Builders/ImageFromDockerfileBuilder.cs b/src/Testcontainers/Builders/ImageFromDockerfileBuilder.cs index c48a0f4f3..3b5e24da8 100644 --- a/src/Testcontainers/Builders/ImageFromDockerfileBuilder.cs +++ b/src/Testcontainers/Builders/ImageFromDockerfileBuilder.cs @@ -81,7 +81,7 @@ public ImageFromDockerfileBuilder WithDockerfileDirectory(CommonDirectoryPath co } /// - public ImageFromDockerfileBuilder WithImageBuildPolicy(Func imageBuildPolicy) + public ImageFromDockerfileBuilder WithImageBuildPolicy(Func imageBuildPolicy) { return Merge(DockerResourceConfiguration, new ImageFromDockerfileConfiguration(imageBuildPolicy: imageBuildPolicy)); } diff --git a/src/Testcontainers/Clients/DockerContainerOperations.cs b/src/Testcontainers/Clients/DockerContainerOperations.cs index 72121bee0..99f16281d 100644 --- a/src/Testcontainers/Clients/DockerContainerOperations.cs +++ b/src/Testcontainers/Clients/DockerContainerOperations.cs @@ -4,7 +4,6 @@ namespace DotNet.Testcontainers.Clients using System.Collections.Generic; using System.Globalization; using System.IO; - using System.Linq; using System.Threading; using System.Threading.Tasks; using Docker.DotNet.Models; @@ -24,25 +23,29 @@ public DockerContainerOperations(Guid sessionId, IDockerEndpointAuthenticationCo public async Task> GetAllAsync(CancellationToken ct = default) { - return (await Docker.Containers.ListContainersAsync(new ContainersListParameters { All = true }, ct) - .ConfigureAwait(false)).ToArray(); + return await Docker.Containers.ListContainersAsync(new ContainersListParameters { All = true }, ct) + .ConfigureAwait(false); + } + + public async Task> GetAllAsync(FilterByProperty filters, CancellationToken ct = default) + { + return await Docker.Containers.ListContainersAsync(new ContainersListParameters { All = true, Filters = filters }, ct) + .ConfigureAwait(false); } - public Task ByIdAsync(string id, CancellationToken ct = default) + public Task ByIdAsync(string id, CancellationToken ct = default) { return ByPropertyAsync("id", id, ct); } - public Task ByNameAsync(string name, CancellationToken ct = default) + public Task ByNameAsync(string name, CancellationToken ct = default) { return ByPropertyAsync("name", name, ct); } - public async Task ByPropertyAsync(string property, string value, CancellationToken ct = default) + public Task ByPropertyAsync(string property, string value, CancellationToken ct = default) { - var filters = new FilterByProperty { { property, value } }; - return (await Docker.Containers.ListContainersAsync(new ContainersListParameters { All = true, Filters = filters }, ct) - .ConfigureAwait(false)).FirstOrDefault(); + return Docker.Containers.InspectContainerAsync(value, ct); } public async Task ExistsWithIdAsync(string id, CancellationToken ct = default) @@ -214,10 +217,5 @@ public async Task RunAsync(IContainerConfiguration configuration, Cancel _logger.DockerContainerCreated(createContainerResponse.ID); return createContainerResponse.ID; } - - public Task InspectAsync(string id, CancellationToken ct = default) - { - return Docker.Containers.InspectContainerAsync(id, ct); - } } } diff --git a/src/Testcontainers/Clients/DockerImageOperations.cs b/src/Testcontainers/Clients/DockerImageOperations.cs index 8d8a537ac..5f2e2ec5e 100644 --- a/src/Testcontainers/Clients/DockerImageOperations.cs +++ b/src/Testcontainers/Clients/DockerImageOperations.cs @@ -26,26 +26,29 @@ public DockerImageOperations(Guid sessionId, IDockerEndpointAuthenticationConfig public async Task> GetAllAsync(CancellationToken ct = default) { - return (await Docker.Images.ListImagesAsync(new ImagesListParameters { All = true }, ct) - .ConfigureAwait(false)).ToArray(); + return await Docker.Images.ListImagesAsync(new ImagesListParameters { All = true }, ct) + .ConfigureAwait(false); + } + + public async Task> GetAllAsync(FilterByProperty filters, CancellationToken ct = default) + { + return await Docker.Images.ListImagesAsync(new ImagesListParameters { All = true, Filters = filters }, ct) + .ConfigureAwait(false); } - public async Task ByIdAsync(string id, CancellationToken ct = default) + public Task ByIdAsync(string id, CancellationToken ct = default) { - return (await GetAllAsync(ct) - .ConfigureAwait(false)).FirstOrDefault(image => image.ID.Equals(id, StringComparison.OrdinalIgnoreCase)); + return ByPropertyAsync("id", id, ct); } - public Task ByNameAsync(string name, CancellationToken ct = default) + public Task ByNameAsync(string name, CancellationToken ct = default) { - return ByPropertyAsync("reference", name, ct); + return ByPropertyAsync("name", name, ct); } - public async Task ByPropertyAsync(string property, string value, CancellationToken ct = default) + public Task ByPropertyAsync(string property, string value, CancellationToken ct = default) { - var filters = new FilterByProperty { { property, value } }; - return (await Docker.Images.ListImagesAsync(new ImagesListParameters { All = true, Filters = filters }, ct) - .ConfigureAwait(false)).FirstOrDefault(); + return Docker.Images.InspectImageAsync(value, ct); } public async Task ExistsWithIdAsync(string id, CancellationToken ct = default) diff --git a/src/Testcontainers/Clients/DockerNetworkOperations.cs b/src/Testcontainers/Clients/DockerNetworkOperations.cs index 661105613..1d5b03406 100644 --- a/src/Testcontainers/Clients/DockerNetworkOperations.cs +++ b/src/Testcontainers/Clients/DockerNetworkOperations.cs @@ -21,14 +21,19 @@ public DockerNetworkOperations(Guid sessionId, IDockerEndpointAuthenticationConf public async Task> GetAllAsync(CancellationToken ct = default) { - return (await Docker.Networks.ListNetworksAsync(new NetworksListParameters(), ct) - .ConfigureAwait(false)).ToArray(); + return await Docker.Networks.ListNetworksAsync(new NetworksListParameters(), ct) + .ConfigureAwait(false); + } + + public async Task> GetAllAsync(FilterByProperty filters, CancellationToken ct = default) + { + return await Docker.Networks.ListNetworksAsync(new NetworksListParameters { Filters = filters }, ct) + .ConfigureAwait(false); } - public async Task ByIdAsync(string id, CancellationToken ct = default) + public Task ByIdAsync(string id, CancellationToken ct = default) { - return (await GetAllAsync(ct) - .ConfigureAwait(false)).FirstOrDefault(image => image.ID.Equals(id, StringComparison.OrdinalIgnoreCase)); + return ByPropertyAsync("id", id, ct); } public Task ByNameAsync(string name, CancellationToken ct = default) @@ -36,11 +41,9 @@ public Task ByNameAsync(string name, CancellationToken ct = def return ByPropertyAsync("name", name, ct); } - public async Task ByPropertyAsync(string property, string value, CancellationToken ct = default) + public Task ByPropertyAsync(string property, string value, CancellationToken ct = default) { - var filters = new FilterByProperty { { property, value } }; - return (await Docker.Networks.ListNetworksAsync(new NetworksListParameters { Filters = filters }, ct) - .ConfigureAwait(false)).FirstOrDefault(); + return Docker.Networks.InspectNetworkAsync(value, ct); } public async Task ExistsWithIdAsync(string id, CancellationToken ct = default) diff --git a/src/Testcontainers/Clients/DockerVolumeOperations.cs b/src/Testcontainers/Clients/DockerVolumeOperations.cs index cd31e0cf4..2b379852a 100644 --- a/src/Testcontainers/Clients/DockerVolumeOperations.cs +++ b/src/Testcontainers/Clients/DockerVolumeOperations.cs @@ -21,13 +21,23 @@ public DockerVolumeOperations(Guid sessionId, IDockerEndpointAuthenticationConfi public async Task> GetAllAsync(CancellationToken ct = default) { - return (await Docker.Volumes.ListAsync(ct) - .ConfigureAwait(false)).Volumes.ToArray(); + var response = await Docker.Volumes.ListAsync(ct) + .ConfigureAwait(false); + + return response.Volumes; + } + + public async Task> GetAllAsync(FilterByProperty filters, CancellationToken ct = default) + { + var response = await Docker.Volumes.ListAsync(new VolumesListParameters { Filters = filters }, ct) + .ConfigureAwait(false); + + return response.Volumes; } public Task ByIdAsync(string id, CancellationToken ct = default) { - return Task.FromResult(null); + return ByPropertyAsync("id", id, ct); } public Task ByNameAsync(string name, CancellationToken ct = default) @@ -35,11 +45,9 @@ public Task ByNameAsync(string name, CancellationToken ct = defa return ByPropertyAsync("name", name, ct); } - public async Task ByPropertyAsync(string property, string value, CancellationToken ct = default) + public Task ByPropertyAsync(string property, string value, CancellationToken ct = default) { - var filters = new FilterByProperty { { property, value } }; - return (await Docker.Volumes.ListAsync(new VolumesListParameters { Filters = filters }, ct) - .ConfigureAwait(false)).Volumes.FirstOrDefault(); + return Docker.Volumes.InspectAsync(value, ct); } public async Task ExistsWithIdAsync(string id, CancellationToken ct = default) diff --git a/src/Testcontainers/Clients/IDockerContainerOperations.cs b/src/Testcontainers/Clients/IDockerContainerOperations.cs index ea833ee08..1557074a7 100644 --- a/src/Testcontainers/Clients/IDockerContainerOperations.cs +++ b/src/Testcontainers/Clients/IDockerContainerOperations.cs @@ -9,7 +9,7 @@ namespace DotNet.Testcontainers.Clients using DotNet.Testcontainers.Configurations; using DotNet.Testcontainers.Containers; - internal interface IDockerContainerOperations : IHasListOperations + internal interface IDockerContainerOperations : IHasListOperations { Task GetExitCodeAsync(string id, CancellationToken ct = default); @@ -30,7 +30,5 @@ internal interface IDockerContainerOperations : IHasListOperations ExecAsync(string id, IList command, CancellationToken ct = default); Task RunAsync(IContainerConfiguration configuration, CancellationToken ct = default); - - Task InspectAsync(string id, CancellationToken ct = default); } } diff --git a/src/Testcontainers/Clients/IDockerImageOperations.cs b/src/Testcontainers/Clients/IDockerImageOperations.cs index bb94950f2..f93cdf70d 100644 --- a/src/Testcontainers/Clients/IDockerImageOperations.cs +++ b/src/Testcontainers/Clients/IDockerImageOperations.cs @@ -6,7 +6,7 @@ namespace DotNet.Testcontainers.Clients using DotNet.Testcontainers.Configurations; using DotNet.Testcontainers.Images; - internal interface IDockerImageOperations : IHasListOperations + internal interface IDockerImageOperations : IHasListOperations { Task CreateAsync(IImage image, IDockerRegistryAuthenticationConfiguration dockerRegistryAuthConfig, CancellationToken ct = default); diff --git a/src/Testcontainers/Clients/IDockerNetworkOperations.cs b/src/Testcontainers/Clients/IDockerNetworkOperations.cs index 9f4fe6afb..b9cfb4bf0 100644 --- a/src/Testcontainers/Clients/IDockerNetworkOperations.cs +++ b/src/Testcontainers/Clients/IDockerNetworkOperations.cs @@ -5,7 +5,7 @@ namespace DotNet.Testcontainers.Clients using Docker.DotNet.Models; using DotNet.Testcontainers.Configurations; - internal interface IDockerNetworkOperations : IHasListOperations + internal interface IDockerNetworkOperations : IHasListOperations { Task CreateAsync(INetworkConfiguration configuration, CancellationToken ct = default); diff --git a/src/Testcontainers/Clients/IDockerVolumeOperations.cs b/src/Testcontainers/Clients/IDockerVolumeOperations.cs index e9fbee316..05a63de08 100644 --- a/src/Testcontainers/Clients/IDockerVolumeOperations.cs +++ b/src/Testcontainers/Clients/IDockerVolumeOperations.cs @@ -5,7 +5,7 @@ namespace DotNet.Testcontainers.Clients using Docker.DotNet.Models; using DotNet.Testcontainers.Configurations; - internal interface IDockerVolumeOperations : IHasListOperations + internal interface IDockerVolumeOperations : IHasListOperations { Task CreateAsync(IVolumeConfiguration configuration, CancellationToken ct = default); diff --git a/src/Testcontainers/Clients/IHasListOperations.cs b/src/Testcontainers/Clients/IHasListOperations.cs index 6a5f07db3..e22229e6b 100644 --- a/src/Testcontainers/Clients/IHasListOperations.cs +++ b/src/Testcontainers/Clients/IHasListOperations.cs @@ -4,15 +4,17 @@ namespace DotNet.Testcontainers.Clients using System.Threading; using System.Threading.Tasks; - internal interface IHasListOperations + internal interface IHasListOperations { - Task> GetAllAsync(CancellationToken ct = default); + Task> GetAllAsync(CancellationToken ct = default); - Task ByIdAsync(string id, CancellationToken ct = default); + Task> GetAllAsync(FilterByProperty filters, CancellationToken ct = default); - Task ByNameAsync(string name, CancellationToken ct = default); + Task ByIdAsync(string id, CancellationToken ct = default); - Task ByPropertyAsync(string property, string value, CancellationToken ct = default); + Task ByNameAsync(string name, CancellationToken ct = default); + + Task ByPropertyAsync(string property, string value, CancellationToken ct = default); Task ExistsWithIdAsync(string id, CancellationToken ct = default); diff --git a/src/Testcontainers/Clients/ITestcontainersClient.cs b/src/Testcontainers/Clients/ITestcontainersClient.cs index dcb8b6554..011156732 100644 --- a/src/Testcontainers/Clients/ITestcontainersClient.cs +++ b/src/Testcontainers/Clients/ITestcontainersClient.cs @@ -63,14 +63,6 @@ internal interface ITestcontainersClient /// Task that gets the container logs. Task<(string Stdout, string Stderr)> GetContainerLogsAsync(string id, DateTime since = default, DateTime until = default, bool timestampsEnabled = true, CancellationToken ct = default); - /// - /// Gets the container low-level information object. - /// - /// The container id. - /// Cancellation token. - /// Task that gets the container low-level information object. - Task InspectContainerAsync(string id, CancellationToken ct = default); - /// /// Starts the container. /// diff --git a/src/Testcontainers/Clients/TestcontainersClient.cs b/src/Testcontainers/Clients/TestcontainersClient.cs index 9ff769a47..62401bda3 100644 --- a/src/Testcontainers/Clients/TestcontainersClient.cs +++ b/src/Testcontainers/Clients/TestcontainersClient.cs @@ -118,12 +118,6 @@ public Task GetContainerExitCodeAsync(string id, CancellationToken ct = de return Container.GetLogsAsync(id, since.ToUniversalTime().Subtract(unixEpoch), until.ToUniversalTime().Subtract(unixEpoch), timestampsEnabled, ct); } - /// - public Task InspectContainerAsync(string id, CancellationToken ct = default) - { - return Container.InspectAsync(id, ct); - } - /// public async Task StartAsync(string id, CancellationToken ct = default) { diff --git a/src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs b/src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs index 46b3c4b94..0a4b6092d 100644 --- a/src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs +++ b/src/Testcontainers/Configurations/Containers/ContainerConfiguration.cs @@ -42,7 +42,7 @@ public class ContainerConfiguration : ResourceConfigurationA value indicating whether the privileged flag is set or not. public ContainerConfiguration( IImage image = null, - Func imagePullPolicy = null, + Func imagePullPolicy = null, string name = null, string hostname = null, string macAddress = null, @@ -148,7 +148,7 @@ public ContainerConfiguration(IContainerConfiguration oldValue, IContainerConfig public IImage Image { get; } /// - public Func ImagePullPolicy { get; } + public Func ImagePullPolicy { get; } /// public string Name { get; } diff --git a/src/Testcontainers/Configurations/Containers/IContainerConfiguration.cs b/src/Testcontainers/Configurations/Containers/IContainerConfiguration.cs index 830f1668b..8c10cb360 100644 --- a/src/Testcontainers/Configurations/Containers/IContainerConfiguration.cs +++ b/src/Testcontainers/Configurations/Containers/IContainerConfiguration.cs @@ -34,7 +34,7 @@ public interface IContainerConfiguration : IResourceConfiguration /// Gets the image pull policy. /// - Func ImagePullPolicy { get; } + Func ImagePullPolicy { get; } /// /// Gets the name. diff --git a/src/Testcontainers/Configurations/Images/IImageFromDockerfileConfiguration.cs b/src/Testcontainers/Configurations/Images/IImageFromDockerfileConfiguration.cs index 8f27b3aef..eac754820 100644 --- a/src/Testcontainers/Configurations/Images/IImageFromDockerfileConfiguration.cs +++ b/src/Testcontainers/Configurations/Images/IImageFromDockerfileConfiguration.cs @@ -35,7 +35,7 @@ public interface IImageFromDockerfileConfiguration : IResourceConfiguration /// Gets the image build policy. /// - Func ImageBuildPolicy { get; } + Func ImageBuildPolicy { get; } /// /// Gets a list of build arguments. diff --git a/src/Testcontainers/Configurations/Images/ImageFromDockerfileConfiguration.cs b/src/Testcontainers/Configurations/Images/ImageFromDockerfileConfiguration.cs index 2677afe2c..9203c30d9 100644 --- a/src/Testcontainers/Configurations/Images/ImageFromDockerfileConfiguration.cs +++ b/src/Testcontainers/Configurations/Images/ImageFromDockerfileConfiguration.cs @@ -24,7 +24,7 @@ public ImageFromDockerfileConfiguration( string dockerfile = null, string dockerfileDirectory = null, IImage image = null, - Func imageBuildPolicy = null, + Func imageBuildPolicy = null, IReadOnlyDictionary buildArguments = null, bool? deleteIfExists = null) { @@ -83,7 +83,7 @@ public ImageFromDockerfileConfiguration(IImageFromDockerfileConfiguration oldVal public IImage Image { get; } /// - public Func ImageBuildPolicy { get; } + public Func ImageBuildPolicy { get; } /// public IReadOnlyDictionary BuildArguments { get; } diff --git a/src/Testcontainers/Containers/DockerContainer.cs b/src/Testcontainers/Containers/DockerContainer.cs index 3127a9962..e7db53b33 100644 --- a/src/Testcontainers/Containers/DockerContainer.cs +++ b/src/Testcontainers/Containers/DockerContainer.cs @@ -368,7 +368,7 @@ protected override async Task UnsafeCreateAsync(CancellationToken ct = default) var id = await _client.RunAsync(_configuration, ct) .ConfigureAwait(false); - _container = await _client.InspectContainerAsync(id, ct) + _container = await _client.Container.ByIdAsync(id, ct) .ConfigureAwait(false); Created?.Invoke(this, EventArgs.Empty); @@ -407,7 +407,7 @@ protected virtual async Task UnsafeStartAsync(CancellationToken ct = default) async Task CheckPortBindingsAsync() { - _container = await _client.InspectContainerAsync(_container.ID, ct) + _container = await _client.Container.ByIdAsync(_container.ID, ct) .ConfigureAwait(false); var boundPorts = _container.NetworkSettings.Ports.Values.Where(portBindings => portBindings != null).SelectMany(portBinding => portBinding).Count(portBinding => !string.IsNullOrEmpty(portBinding.HostPort)); @@ -416,7 +416,7 @@ async Task CheckPortBindingsAsync() async Task CheckWaitStrategyAsync(IWaitUntil wait) { - _container = await _client.InspectContainerAsync(_container.ID, ct) + _container = await _client.Container.ByIdAsync(_container.ID, ct) .ConfigureAwait(false); return await wait.UntilAsync(this) @@ -474,7 +474,7 @@ await _client.StopAsync(_container.ID, ct) try { - _container = await _client.InspectContainerAsync(_container.ID, ct) + _container = await _client.Container.ByIdAsync(_container.ID, ct) .ConfigureAwait(false); } catch (DockerApiException) diff --git a/src/Testcontainers/Images/FutureDockerImage.cs b/src/Testcontainers/Images/FutureDockerImage.cs index 4352f6f15..bb3b2be13 100644 --- a/src/Testcontainers/Images/FutureDockerImage.cs +++ b/src/Testcontainers/Images/FutureDockerImage.cs @@ -16,7 +16,7 @@ internal sealed class FutureDockerImage : Resource, IFutureDockerImage private readonly IImageFromDockerfileConfiguration _configuration; - private ImagesListResponse _image = new ImagesListResponse(); + private ImageInspectResponse _image = new ImageInspectResponse(); /// /// Initializes a new instance of the class. @@ -132,7 +132,7 @@ protected override async Task UnsafeDeleteAsync(CancellationToken ct = default) await _client.Image.DeleteAsync(_configuration.Image, ct) .ConfigureAwait(false); - _image = new ImagesListResponse(); + _image = new ImageInspectResponse(); } } } diff --git a/src/Testcontainers/Images/PullPolicy.cs b/src/Testcontainers/Images/PullPolicy.cs index 9b879f54f..b5a852d2c 100644 --- a/src/Testcontainers/Images/PullPolicy.cs +++ b/src/Testcontainers/Images/PullPolicy.cs @@ -13,7 +13,7 @@ public static class PullPolicy /// /// Gets the policy that never pulls images. /// - public static Func Never + public static Func Never { get { @@ -24,7 +24,7 @@ public static Func Never /// /// Gets the policy that pulls missing images (not cached). /// - public static Func Missing + public static Func Missing { get { @@ -35,7 +35,7 @@ public static Func Missing /// /// Gets the policy that always pulls images. /// - public static Func Always + public static Func Always { get { diff --git a/src/Testcontainers/Volumes/DockerVolume.cs b/src/Testcontainers/Volumes/DockerVolume.cs index 91c2aeeed..b161c0e8e 100644 --- a/src/Testcontainers/Volumes/DockerVolume.cs +++ b/src/Testcontainers/Volumes/DockerVolume.cs @@ -94,10 +94,10 @@ protected override async Task UnsafeCreateAsync(CancellationToken ct = default) return; } - var name = await _client.Volume.CreateAsync(_configuration, ct) + var id = await _client.Volume.CreateAsync(_configuration, ct) .ConfigureAwait(false); - _volume = await _client.Volume.ByNameAsync(name, ct) + _volume = await _client.Volume.ByIdAsync(id, ct) .ConfigureAwait(false); } From 93471ca151d920cb7c190d531564a7d4c3056b05 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Tue, 10 Oct 2023 18:40:26 +0200 Subject: [PATCH 2/4] fix: Catch no such resource exception --- .../Clients/DockerContainerOperations.cs | 27 ++++++++++++++----- .../Clients/DockerImageOperations.cs | 27 ++++++++++++++----- .../Clients/DockerNetworkOperations.cs | 27 ++++++++++++++----- .../Clients/DockerVolumeOperations.cs | 27 ++++++++++++++----- 4 files changed, 84 insertions(+), 24 deletions(-) diff --git a/src/Testcontainers/Clients/DockerContainerOperations.cs b/src/Testcontainers/Clients/DockerContainerOperations.cs index 99f16281d..b4d4f0165 100644 --- a/src/Testcontainers/Clients/DockerContainerOperations.cs +++ b/src/Testcontainers/Clients/DockerContainerOperations.cs @@ -6,6 +6,7 @@ namespace DotNet.Testcontainers.Clients using System.IO; using System.Threading; using System.Threading.Tasks; + using Docker.DotNet; using Docker.DotNet.Models; using DotNet.Testcontainers.Configurations; using DotNet.Testcontainers.Containers; @@ -13,6 +14,8 @@ namespace DotNet.Testcontainers.Clients internal sealed class DockerContainerOperations : DockerApiClient, IDockerContainerOperations { + private static readonly ContainerInspectResponse NoSuchContainer = new ContainerInspectResponse(); + private readonly ILogger _logger; public DockerContainerOperations(Guid sessionId, IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig, ILogger logger) @@ -43,21 +46,33 @@ public Task ByNameAsync(string name, CancellationToken return ByPropertyAsync("name", name, ct); } - public Task ByPropertyAsync(string property, string value, CancellationToken ct = default) + public async Task ByPropertyAsync(string property, string value, CancellationToken ct = default) { - return Docker.Containers.InspectContainerAsync(value, ct); + try + { + return await Docker.Containers.InspectContainerAsync(value, ct) + .ConfigureAwait(false); + } + catch (DockerApiException) + { + return NoSuchContainer; + } } public async Task ExistsWithIdAsync(string id, CancellationToken ct = default) { - return await ByIdAsync(id, ct) - .ConfigureAwait(false) != null; + var response = await ByIdAsync(id, ct) + .ConfigureAwait(false); + + return !NoSuchContainer.Equals(response); } public async Task ExistsWithNameAsync(string name, CancellationToken ct = default) { - return await ByNameAsync(name, ct) - .ConfigureAwait(false) != null; + var response = await ByNameAsync(name, ct) + .ConfigureAwait(false); + + return !NoSuchContainer.Equals(response); } public async Task GetExitCodeAsync(string id, CancellationToken ct = default) diff --git a/src/Testcontainers/Clients/DockerImageOperations.cs b/src/Testcontainers/Clients/DockerImageOperations.cs index 5f2e2ec5e..09e60feaa 100644 --- a/src/Testcontainers/Clients/DockerImageOperations.cs +++ b/src/Testcontainers/Clients/DockerImageOperations.cs @@ -6,6 +6,7 @@ namespace DotNet.Testcontainers.Clients using System.Linq; using System.Threading; using System.Threading.Tasks; + using Docker.DotNet; using Docker.DotNet.Models; using DotNet.Testcontainers.Configurations; using DotNet.Testcontainers.Images; @@ -13,6 +14,8 @@ namespace DotNet.Testcontainers.Clients internal sealed class DockerImageOperations : DockerApiClient, IDockerImageOperations { + private static readonly ImageInspectResponse NoSuchImage = new ImageInspectResponse(); + private readonly ILogger _logger; private readonly TraceProgress _traceProgress; @@ -46,21 +49,33 @@ public Task ByNameAsync(string name, CancellationToken ct return ByPropertyAsync("name", name, ct); } - public Task ByPropertyAsync(string property, string value, CancellationToken ct = default) + public async Task ByPropertyAsync(string property, string value, CancellationToken ct = default) { - return Docker.Images.InspectImageAsync(value, ct); + try + { + return await Docker.Images.InspectImageAsync(value, ct) + .ConfigureAwait(false); + } + catch (DockerApiException) + { + return NoSuchImage; + } } public async Task ExistsWithIdAsync(string id, CancellationToken ct = default) { - return await ByIdAsync(id, ct) - .ConfigureAwait(false) != null; + var response = await ByIdAsync(id, ct) + .ConfigureAwait(false); + + return !NoSuchImage.Equals(response); } public async Task ExistsWithNameAsync(string name, CancellationToken ct = default) { - return await ByNameAsync(name, ct) - .ConfigureAwait(false) != null; + var response = await ByNameAsync(name, ct) + .ConfigureAwait(false); + + return !NoSuchImage.Equals(response); } public async Task CreateAsync(IImage image, IDockerRegistryAuthenticationConfiguration dockerRegistryAuthConfig, CancellationToken ct = default) diff --git a/src/Testcontainers/Clients/DockerNetworkOperations.cs b/src/Testcontainers/Clients/DockerNetworkOperations.cs index 1d5b03406..2b5f8f0b1 100644 --- a/src/Testcontainers/Clients/DockerNetworkOperations.cs +++ b/src/Testcontainers/Clients/DockerNetworkOperations.cs @@ -5,12 +5,15 @@ namespace DotNet.Testcontainers.Clients using System.Linq; using System.Threading; using System.Threading.Tasks; + using Docker.DotNet; using Docker.DotNet.Models; using DotNet.Testcontainers.Configurations; using Microsoft.Extensions.Logging; internal sealed class DockerNetworkOperations : DockerApiClient, IDockerNetworkOperations { + private static readonly NetworkResponse NoSuchNetwork = new NetworkResponse(); + private readonly ILogger _logger; public DockerNetworkOperations(Guid sessionId, IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig, ILogger logger) @@ -41,21 +44,33 @@ public Task ByNameAsync(string name, CancellationToken ct = def return ByPropertyAsync("name", name, ct); } - public Task ByPropertyAsync(string property, string value, CancellationToken ct = default) + public async Task ByPropertyAsync(string property, string value, CancellationToken ct = default) { - return Docker.Networks.InspectNetworkAsync(value, ct); + try + { + return await Docker.Networks.InspectNetworkAsync(value, ct) + .ConfigureAwait(false); + } + catch (DockerApiException) + { + return NoSuchNetwork; + } } public async Task ExistsWithIdAsync(string id, CancellationToken ct = default) { - return await ByIdAsync(id, ct) - .ConfigureAwait(false) != null; + var response = await ByIdAsync(id, ct) + .ConfigureAwait(false); + + return !NoSuchNetwork.Equals(response); } public async Task ExistsWithNameAsync(string name, CancellationToken ct = default) { - return await ByNameAsync(name, ct) - .ConfigureAwait(false) != null; + var response = await ByNameAsync(name, ct) + .ConfigureAwait(false); + + return !NoSuchNetwork.Equals(response); } public async Task CreateAsync(INetworkConfiguration configuration, CancellationToken ct = default) diff --git a/src/Testcontainers/Clients/DockerVolumeOperations.cs b/src/Testcontainers/Clients/DockerVolumeOperations.cs index 2b379852a..350b6c4cc 100644 --- a/src/Testcontainers/Clients/DockerVolumeOperations.cs +++ b/src/Testcontainers/Clients/DockerVolumeOperations.cs @@ -5,12 +5,15 @@ namespace DotNet.Testcontainers.Clients using System.Linq; using System.Threading; using System.Threading.Tasks; + using Docker.DotNet; using Docker.DotNet.Models; using DotNet.Testcontainers.Configurations; using Microsoft.Extensions.Logging; internal sealed class DockerVolumeOperations : DockerApiClient, IDockerVolumeOperations { + private static readonly VolumeResponse NoSuchVolume = new VolumeResponse(); + private readonly ILogger _logger; public DockerVolumeOperations(Guid sessionId, IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig, ILogger logger) @@ -45,21 +48,33 @@ public Task ByNameAsync(string name, CancellationToken ct = defa return ByPropertyAsync("name", name, ct); } - public Task ByPropertyAsync(string property, string value, CancellationToken ct = default) + public async Task ByPropertyAsync(string property, string value, CancellationToken ct = default) { - return Docker.Volumes.InspectAsync(value, ct); + try + { + return await Docker.Volumes.InspectAsync(value, ct) + .ConfigureAwait(false); + } + catch (DockerApiException) + { + return NoSuchVolume; + } } public async Task ExistsWithIdAsync(string id, CancellationToken ct = default) { - return await ByIdAsync(id, ct) - .ConfigureAwait(false) != null; + var response = await ByIdAsync(id, ct) + .ConfigureAwait(false); + + return !NoSuchVolume.Equals(response); } public async Task ExistsWithNameAsync(string name, CancellationToken ct = default) { - return await ByNameAsync(name, ct) - .ConfigureAwait(false) != null; + var response = await ByNameAsync(name, ct) + .ConfigureAwait(false); + + return !NoSuchVolume.Equals(response); } public async Task CreateAsync(IVolumeConfiguration configuration, CancellationToken ct = default) From 0da59d7ade3ff65c612f84d37058d050b75f4a28 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:02:58 +0200 Subject: [PATCH 3/4] fix: Use NoSuchImage instance in PullPolicy predicate --- src/Testcontainers/Clients/DockerImageOperations.cs | 6 +++--- src/Testcontainers/Clients/ITestcontainersClient.cs | 1 - src/Testcontainers/Clients/TestcontainersClient.cs | 1 - src/Testcontainers/Images/PullPolicy.cs | 3 ++- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Testcontainers/Clients/DockerImageOperations.cs b/src/Testcontainers/Clients/DockerImageOperations.cs index 09e60feaa..d23e47f23 100644 --- a/src/Testcontainers/Clients/DockerImageOperations.cs +++ b/src/Testcontainers/Clients/DockerImageOperations.cs @@ -14,12 +14,12 @@ namespace DotNet.Testcontainers.Clients internal sealed class DockerImageOperations : DockerApiClient, IDockerImageOperations { - private static readonly ImageInspectResponse NoSuchImage = new ImageInspectResponse(); - private readonly ILogger _logger; private readonly TraceProgress _traceProgress; + public static readonly ImageInspectResponse NoSuchImage = new ImageInspectResponse(); + public DockerImageOperations(Guid sessionId, IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig, ILogger logger) : base(sessionId, dockerEndpointAuthConfig) { @@ -46,7 +46,7 @@ public Task ByIdAsync(string id, CancellationToken ct = de public Task ByNameAsync(string name, CancellationToken ct = default) { - return ByPropertyAsync("name", name, ct); + return ByPropertyAsync("reference", name, ct); } public async Task ByPropertyAsync(string property, string value, CancellationToken ct = default) diff --git a/src/Testcontainers/Clients/ITestcontainersClient.cs b/src/Testcontainers/Clients/ITestcontainersClient.cs index 011156732..1cc5c641b 100644 --- a/src/Testcontainers/Clients/ITestcontainersClient.cs +++ b/src/Testcontainers/Clients/ITestcontainersClient.cs @@ -5,7 +5,6 @@ namespace DotNet.Testcontainers.Clients using System.IO; using System.Threading; using System.Threading.Tasks; - using Docker.DotNet.Models; using DotNet.Testcontainers.Configurations; using DotNet.Testcontainers.Containers; diff --git a/src/Testcontainers/Clients/TestcontainersClient.cs b/src/Testcontainers/Clients/TestcontainersClient.cs index 62401bda3..2d9e45587 100644 --- a/src/Testcontainers/Clients/TestcontainersClient.cs +++ b/src/Testcontainers/Clients/TestcontainersClient.cs @@ -9,7 +9,6 @@ namespace DotNet.Testcontainers.Clients using System.Threading; using System.Threading.Tasks; using Docker.DotNet; - using Docker.DotNet.Models; using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Configurations; using DotNet.Testcontainers.Containers; diff --git a/src/Testcontainers/Images/PullPolicy.cs b/src/Testcontainers/Images/PullPolicy.cs index b5a852d2c..73a3dfb44 100644 --- a/src/Testcontainers/Images/PullPolicy.cs +++ b/src/Testcontainers/Images/PullPolicy.cs @@ -2,6 +2,7 @@ namespace DotNet.Testcontainers.Images { using System; using Docker.DotNet.Models; + using DotNet.Testcontainers.Clients; using JetBrains.Annotations; /// @@ -28,7 +29,7 @@ public static Func Missing { get { - return cachedImage => cachedImage == null; + return cachedImage => DockerImageOperations.NoSuchImage.Equals(cachedImage); } } From b0b0acbf57ac152cf8a10d93a83ea6480b0a11f8 Mon Sep 17 00:00:00 2001 From: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:34:29 +0200 Subject: [PATCH 4/4] chore: Do not return default resource type --- src/Testcontainers/Clients/DockerContainerOperations.cs | 8 +++----- src/Testcontainers/Clients/DockerImageOperations.cs | 8 +++----- src/Testcontainers/Clients/DockerNetworkOperations.cs | 8 +++----- src/Testcontainers/Clients/DockerVolumeOperations.cs | 8 +++----- src/Testcontainers/Images/PullPolicy.cs | 3 +-- 5 files changed, 13 insertions(+), 22 deletions(-) diff --git a/src/Testcontainers/Clients/DockerContainerOperations.cs b/src/Testcontainers/Clients/DockerContainerOperations.cs index b4d4f0165..de7526acc 100644 --- a/src/Testcontainers/Clients/DockerContainerOperations.cs +++ b/src/Testcontainers/Clients/DockerContainerOperations.cs @@ -14,8 +14,6 @@ namespace DotNet.Testcontainers.Clients internal sealed class DockerContainerOperations : DockerApiClient, IDockerContainerOperations { - private static readonly ContainerInspectResponse NoSuchContainer = new ContainerInspectResponse(); - private readonly ILogger _logger; public DockerContainerOperations(Guid sessionId, IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig, ILogger logger) @@ -55,7 +53,7 @@ public async Task ByPropertyAsync(string property, str } catch (DockerApiException) { - return NoSuchContainer; + return null; } } @@ -64,7 +62,7 @@ public async Task ExistsWithIdAsync(string id, CancellationToken ct = defa var response = await ByIdAsync(id, ct) .ConfigureAwait(false); - return !NoSuchContainer.Equals(response); + return response != null; } public async Task ExistsWithNameAsync(string name, CancellationToken ct = default) @@ -72,7 +70,7 @@ public async Task ExistsWithNameAsync(string name, CancellationToken ct = var response = await ByNameAsync(name, ct) .ConfigureAwait(false); - return !NoSuchContainer.Equals(response); + return response != null; } public async Task GetExitCodeAsync(string id, CancellationToken ct = default) diff --git a/src/Testcontainers/Clients/DockerImageOperations.cs b/src/Testcontainers/Clients/DockerImageOperations.cs index d23e47f23..f469bd569 100644 --- a/src/Testcontainers/Clients/DockerImageOperations.cs +++ b/src/Testcontainers/Clients/DockerImageOperations.cs @@ -18,8 +18,6 @@ internal sealed class DockerImageOperations : DockerApiClient, IDockerImageOpera private readonly TraceProgress _traceProgress; - public static readonly ImageInspectResponse NoSuchImage = new ImageInspectResponse(); - public DockerImageOperations(Guid sessionId, IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig, ILogger logger) : base(sessionId, dockerEndpointAuthConfig) { @@ -58,7 +56,7 @@ public async Task ByPropertyAsync(string property, string } catch (DockerApiException) { - return NoSuchImage; + return null; } } @@ -67,7 +65,7 @@ public async Task ExistsWithIdAsync(string id, CancellationToken ct = defa var response = await ByIdAsync(id, ct) .ConfigureAwait(false); - return !NoSuchImage.Equals(response); + return response != null; } public async Task ExistsWithNameAsync(string name, CancellationToken ct = default) @@ -75,7 +73,7 @@ public async Task ExistsWithNameAsync(string name, CancellationToken ct = var response = await ByNameAsync(name, ct) .ConfigureAwait(false); - return !NoSuchImage.Equals(response); + return response != null; } public async Task CreateAsync(IImage image, IDockerRegistryAuthenticationConfiguration dockerRegistryAuthConfig, CancellationToken ct = default) diff --git a/src/Testcontainers/Clients/DockerNetworkOperations.cs b/src/Testcontainers/Clients/DockerNetworkOperations.cs index 2b5f8f0b1..503db9c0e 100644 --- a/src/Testcontainers/Clients/DockerNetworkOperations.cs +++ b/src/Testcontainers/Clients/DockerNetworkOperations.cs @@ -12,8 +12,6 @@ namespace DotNet.Testcontainers.Clients internal sealed class DockerNetworkOperations : DockerApiClient, IDockerNetworkOperations { - private static readonly NetworkResponse NoSuchNetwork = new NetworkResponse(); - private readonly ILogger _logger; public DockerNetworkOperations(Guid sessionId, IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig, ILogger logger) @@ -53,7 +51,7 @@ public async Task ByPropertyAsync(string property, string value } catch (DockerApiException) { - return NoSuchNetwork; + return null; } } @@ -62,7 +60,7 @@ public async Task ExistsWithIdAsync(string id, CancellationToken ct = defa var response = await ByIdAsync(id, ct) .ConfigureAwait(false); - return !NoSuchNetwork.Equals(response); + return response != null; } public async Task ExistsWithNameAsync(string name, CancellationToken ct = default) @@ -70,7 +68,7 @@ public async Task ExistsWithNameAsync(string name, CancellationToken ct = var response = await ByNameAsync(name, ct) .ConfigureAwait(false); - return !NoSuchNetwork.Equals(response); + return response != null; } public async Task CreateAsync(INetworkConfiguration configuration, CancellationToken ct = default) diff --git a/src/Testcontainers/Clients/DockerVolumeOperations.cs b/src/Testcontainers/Clients/DockerVolumeOperations.cs index 350b6c4cc..4224bd92b 100644 --- a/src/Testcontainers/Clients/DockerVolumeOperations.cs +++ b/src/Testcontainers/Clients/DockerVolumeOperations.cs @@ -12,8 +12,6 @@ namespace DotNet.Testcontainers.Clients internal sealed class DockerVolumeOperations : DockerApiClient, IDockerVolumeOperations { - private static readonly VolumeResponse NoSuchVolume = new VolumeResponse(); - private readonly ILogger _logger; public DockerVolumeOperations(Guid sessionId, IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig, ILogger logger) @@ -57,7 +55,7 @@ public async Task ByPropertyAsync(string property, string value, } catch (DockerApiException) { - return NoSuchVolume; + return null; } } @@ -66,7 +64,7 @@ public async Task ExistsWithIdAsync(string id, CancellationToken ct = defa var response = await ByIdAsync(id, ct) .ConfigureAwait(false); - return !NoSuchVolume.Equals(response); + return response != null; } public async Task ExistsWithNameAsync(string name, CancellationToken ct = default) @@ -74,7 +72,7 @@ public async Task ExistsWithNameAsync(string name, CancellationToken ct = var response = await ByNameAsync(name, ct) .ConfigureAwait(false); - return !NoSuchVolume.Equals(response); + return response != null; } public async Task CreateAsync(IVolumeConfiguration configuration, CancellationToken ct = default) diff --git a/src/Testcontainers/Images/PullPolicy.cs b/src/Testcontainers/Images/PullPolicy.cs index 73a3dfb44..b5a852d2c 100644 --- a/src/Testcontainers/Images/PullPolicy.cs +++ b/src/Testcontainers/Images/PullPolicy.cs @@ -2,7 +2,6 @@ namespace DotNet.Testcontainers.Images { using System; using Docker.DotNet.Models; - using DotNet.Testcontainers.Clients; using JetBrains.Annotations; /// @@ -29,7 +28,7 @@ public static Func Missing { get { - return cachedImage => DockerImageOperations.NoSuchImage.Equals(cachedImage); + return cachedImage => cachedImage == null; } }