From 40f14ad3c5ae1ac7339007b641bbc03ead946d76 Mon Sep 17 00:00:00 2001 From: Jacob Marks Date: Sat, 29 Jul 2023 16:59:22 +1000 Subject: [PATCH] Refactor image properties to match DSL Add `IImage.Registry`; Remove `IImage.Name` --- .../Builders/ContainerBuilder`3.cs | 2 +- .../Builders/ImageFromDockerfileBuilder.cs | 2 +- src/Testcontainers/Images/DockerImage.cs | 24 ++++++++-------- .../Images/FutureDockerImage.cs | 8 +++--- src/Testcontainers/Images/IImage.cs | 8 +++--- src/Testcontainers/Images/MatchImage.cs | 28 ++++++------------- .../Fixtures/Images/DockerImageFixture.cs | 26 +++++++++-------- .../Images/DockerImageFixtureSerializable.cs | 14 +++++----- .../Fixtures/Images/HealthCheckFixture.cs | 4 +-- ...ockerRegistryAuthenticationProviderTest.cs | 8 +++--- .../Configurations/ResourcePropertiesTest.cs | 2 +- .../Unit/Images/ImageFromDockerfileTest.cs | 8 +++--- .../Unit/Images/TestcontainersImageTest.cs | 4 +-- 13 files changed, 64 insertions(+), 74 deletions(-) diff --git a/src/Testcontainers/Builders/ContainerBuilder`3.cs b/src/Testcontainers/Builders/ContainerBuilder`3.cs index 9f3c6cf81..599274644 100644 --- a/src/Testcontainers/Builders/ContainerBuilder`3.cs +++ b/src/Testcontainers/Builders/ContainerBuilder`3.cs @@ -80,7 +80,7 @@ public TBuilderEntity WithImage(IImage image) return Clone(new ContainerConfiguration(image: image)); } - return Clone(new ContainerConfiguration(image: new DockerImage(image.Repository, image.Name, image.Tag, TestcontainersSettings.HubImageNamePrefix))); + return Clone(new ContainerConfiguration(image: new DockerImage(image.Registry, image.Repository, image.Tag, TestcontainersSettings.HubImageNamePrefix))); } /// diff --git a/src/Testcontainers/Builders/ImageFromDockerfileBuilder.cs b/src/Testcontainers/Builders/ImageFromDockerfileBuilder.cs index c48a0f4f3..0221e2312 100644 --- a/src/Testcontainers/Builders/ImageFromDockerfileBuilder.cs +++ b/src/Testcontainers/Builders/ImageFromDockerfileBuilder.cs @@ -109,7 +109,7 @@ public override IFutureDockerImage Build() /// protected sealed override ImageFromDockerfileBuilder Init() { - return base.Init().WithImageBuildPolicy(PullPolicy.Always).WithDockerfile("Dockerfile").WithDockerfileDirectory(Directory.GetCurrentDirectory()).WithName(new DockerImage("localhost/testcontainers", Guid.NewGuid().ToString("D"), string.Empty)); + return base.Init().WithImageBuildPolicy(PullPolicy.Always).WithDockerfile("Dockerfile").WithDockerfileDirectory(Directory.GetCurrentDirectory()).WithName(new DockerImage("localhost", $"testcontainers/{Guid.NewGuid():D}", string.Empty)); } /// diff --git a/src/Testcontainers/Images/DockerImage.cs b/src/Testcontainers/Images/DockerImage.cs index 3ce296fdf..6d3493917 100644 --- a/src/Testcontainers/Images/DockerImage.cs +++ b/src/Testcontainers/Images/DockerImage.cs @@ -17,7 +17,7 @@ public sealed class DockerImage : IImage /// /// The image. public DockerImage(IImage image) - : this(image.Repository, image.Name, image.Tag) + : this(image.Registry, image.Repository, image.Tag) { } @@ -35,39 +35,39 @@ public DockerImage(string image) /// /// Initializes a new instance of the class. /// + /// The registry. /// The repository. - /// The name. /// The tag. /// The Docker Hub image name prefix. /// Thrown when any argument is null. - /// "fedora/httpd:version1.0" where "fedora" is the repository, "httpd" the name and "version1.0" the tag. + /// "docker.io/fedora/httpd:version1.0" where "docker.io" is the registry, "fedora/httpd" is the repository and "version1.0" the tag. public DockerImage( + string registry, string repository, - string name, string tag, string hubImageNamePrefix = null) { - _ = Guard.Argument(repository, nameof(repository)) + _ = Guard.Argument(registry, nameof(registry)) .NotNull() .NotUppercase(); - _ = Guard.Argument(name, nameof(name)) + _ = Guard.Argument(repository, nameof(repository)) .NotNull() .NotEmpty() .NotUppercase(); _hubImageNamePrefix = hubImageNamePrefix; + Registry = registry; Repository = repository; - Name = name; Tag = string.IsNullOrEmpty(tag) ? "latest" : tag; } /// - public string Repository { get; } + public string Registry { get; } /// - public string Name { get; } + public string Repository { get; } /// public string Tag { get; } @@ -77,7 +77,7 @@ public string FullName { get { - var imageComponents = new[] { _hubImageNamePrefix, Repository, Name } + var imageComponents = new[] { _hubImageNamePrefix, Registry, Repository } .Where(imageComponent => !string.IsNullOrEmpty(imageComponent)) .Select(imageComponent => imageComponent.Trim('/', ':')) .Where(imageComponent => !string.IsNullOrEmpty(imageComponent)); @@ -88,8 +88,8 @@ public string FullName /// public string GetHostname() { - var firstSegmentOfRepository = (string.IsNullOrEmpty(_hubImageNamePrefix) ? Repository : _hubImageNamePrefix).Split('/')[0]; - return firstSegmentOfRepository.IndexOfAny(new[] { '.', ':' }) >= 0 ? firstSegmentOfRepository : null; + var firstSegmentOfRegistry = (string.IsNullOrEmpty(_hubImageNamePrefix) ? Registry : _hubImageNamePrefix).Split('/')[0]; + return firstSegmentOfRegistry.IndexOfAny(new[] { '.', ':' }) >= 0 ? firstSegmentOfRegistry : null; } } } diff --git a/src/Testcontainers/Images/FutureDockerImage.cs b/src/Testcontainers/Images/FutureDockerImage.cs index 4352f6f15..703f032d0 100644 --- a/src/Testcontainers/Images/FutureDockerImage.cs +++ b/src/Testcontainers/Images/FutureDockerImage.cs @@ -30,22 +30,22 @@ public FutureDockerImage(IImageFromDockerfileConfiguration configuration, ILogge } /// - public string Repository + public string Registry { get { ThrowIfResourceNotFound(); - return _configuration.Image.Repository; + return _configuration.Image.Registry; } } /// - public string Name + public string Repository { get { ThrowIfResourceNotFound(); - return _configuration.Image.Name; + return _configuration.Image.Repository; } } diff --git a/src/Testcontainers/Images/IImage.cs b/src/Testcontainers/Images/IImage.cs index b9badc5d3..c1b5d17a3 100644 --- a/src/Testcontainers/Images/IImage.cs +++ b/src/Testcontainers/Images/IImage.cs @@ -9,16 +9,16 @@ namespace DotNet.Testcontainers.Images public interface IImage { /// - /// Gets the repository. + /// Gets the registry. /// [NotNull] - string Repository { get; } + string Registry { get; } /// - /// Gets the name. + /// Gets the repository. /// [NotNull] - string Name { get; } + string Repository { get; } /// /// Gets the tag. diff --git a/src/Testcontainers/Images/MatchImage.cs b/src/Testcontainers/Images/MatchImage.cs index 8819cdcc7..507780c31 100644 --- a/src/Testcontainers/Images/MatchImage.cs +++ b/src/Testcontainers/Images/MatchImage.cs @@ -1,36 +1,24 @@ namespace DotNet.Testcontainers.Images { - using System; - using System.Linq; + using System.Text.RegularExpressions; internal static class MatchImage { + private static readonly Regex _imagePattern = new Regex(@"^((?[^\.\/\:]+(\.[^\.\/\:]*)+(\:[^\/]+)?|[^\:\/]+(\:[^\/]+)|localhost)\/)?(?[^\:\n]*)(\:(?.+)?)?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture); + public static IImage Match(string image) { _ = Guard.Argument(image, nameof(image)) .NotNull() .NotEmpty(); - var imageComponents = image - .Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - - var repository = string.Join("/", imageComponents - .Take(imageComponents.Length - 1)); - - var name = imageComponents - .Last() - .Split(':') - .DefaultIfEmpty(string.Empty) - .First(); + var match = _imagePattern.Match(image); - var tag = imageComponents - .Last() - .Split(':') - .Skip(1) - .DefaultIfEmpty(string.Empty) - .First(); + var registry = match.Groups[1].Value; + var repository = match.Groups[2].Value; + var tag = match.Groups[3].Value; - return new DockerImage(repository, name, tag); + return new DockerImage(registry, repository, tag); } } } diff --git a/tests/Testcontainers.Tests/Fixtures/Images/DockerImageFixture.cs b/tests/Testcontainers.Tests/Fixtures/Images/DockerImageFixture.cs index 1b8404ad9..36c77f381 100644 --- a/tests/Testcontainers.Tests/Fixtures/Images/DockerImageFixture.cs +++ b/tests/Testcontainers.Tests/Fixtures/Images/DockerImageFixture.cs @@ -7,20 +7,22 @@ public sealed class DockerImageFixture : TheoryData("Repository"); - var name = info.GetValue("Name"); - var tag = info.GetValue("Tag"); - Image = new DockerImage(repository, name, tag); + var registry = info.GetValue(nameof(IImage.Registry)); + var repository = info.GetValue(nameof(IImage.Repository)); + var tag = info.GetValue(nameof(IImage.Tag)); + Image = new DockerImage(registry, repository, tag); } public void Serialize(IXunitSerializationInfo info) { - info.AddValue("Repository", Image.Repository); - info.AddValue("Name", Image.Name); - info.AddValue("Tag", Image.Tag); + info.AddValue(nameof(IImage.Registry), Image.Registry); + info.AddValue(nameof(IImage.Repository), Image.Repository); + info.AddValue(nameof(IImage.Tag), Image.Tag); } } } diff --git a/tests/Testcontainers.Tests/Fixtures/Images/HealthCheckFixture.cs b/tests/Testcontainers.Tests/Fixtures/Images/HealthCheckFixture.cs index db4034d3e..2685d0f86 100644 --- a/tests/Testcontainers.Tests/Fixtures/Images/HealthCheckFixture.cs +++ b/tests/Testcontainers.Tests/Fixtures/Images/HealthCheckFixture.cs @@ -14,9 +14,9 @@ public sealed class HealthCheckFixture : IImage, IAsyncLifetime .WithDockerfileDirectory(Path.Combine(Directory.GetCurrentDirectory(), "Assets", "healthWaitStrategy")) .Build(); - public string Repository => _image.Repository; + public string Registry => _image.Registry; - public string Name => _image.Name; + public string Repository => _image.Repository; public string Tag => _image.Tag; diff --git a/tests/Testcontainers.Tests/Unit/Configurations/DockerRegistryAuthenticationProviderTest.cs b/tests/Testcontainers.Tests/Unit/Configurations/DockerRegistryAuthenticationProviderTest.cs index 11a080559..977946a58 100644 --- a/tests/Testcontainers.Tests/Unit/Configurations/DockerRegistryAuthenticationProviderTest.cs +++ b/tests/Testcontainers.Tests/Unit/Configurations/DockerRegistryAuthenticationProviderTest.cs @@ -44,12 +44,12 @@ public void GetHostnameFromDockerImage(string dockerImageName, string hostname) [Theory] [InlineData("", "docker", "stable")] - [InlineData("fedora", "httpd", "1.0")] - [InlineData("foo/bar", "baz", "1.0.0")] - public void GetHostnameFromHubImageNamePrefix(string repository, string name, string tag) + [InlineData("", "fedora/httpd", "1.0")] + [InlineData("", "foo/bar/baz", "1.0.0")] + public void GetHostnameFromHubImageNamePrefix(string registry, string repository, string tag) { const string hubImageNamePrefix = "myregistry.azurecr.io"; - IImage image = new DockerImage(repository, name, tag, hubImageNamePrefix); + IImage image = new DockerImage(registry, repository, tag, hubImageNamePrefix); Assert.Equal(hubImageNamePrefix, image.GetHostname()); } diff --git a/tests/Testcontainers.Tests/Unit/Configurations/ResourcePropertiesTest.cs b/tests/Testcontainers.Tests/Unit/Configurations/ResourcePropertiesTest.cs index 2e39f06ef..06b62f26d 100644 --- a/tests/Testcontainers.Tests/Unit/Configurations/ResourcePropertiesTest.cs +++ b/tests/Testcontainers.Tests/Unit/Configurations/ResourcePropertiesTest.cs @@ -126,8 +126,8 @@ await Task.CompletedTask .ConfigureAwait(false); // Then + Assert.Throws(() => image.Registry); Assert.Throws(() => image.Repository); - Assert.Throws(() => image.Name); Assert.Throws(() => image.Tag); Assert.Throws(() => image.FullName); Assert.Throws(() => image.GetHostname()); diff --git a/tests/Testcontainers.Tests/Unit/Images/ImageFromDockerfileTest.cs b/tests/Testcontainers.Tests/Unit/Images/ImageFromDockerfileTest.cs index eba21b75e..c036d51d6 100644 --- a/tests/Testcontainers.Tests/Unit/Images/ImageFromDockerfileTest.cs +++ b/tests/Testcontainers.Tests/Unit/Images/ImageFromDockerfileTest.cs @@ -18,7 +18,7 @@ public sealed class ImageFromDockerfileTest public async Task DockerfileArchiveTar() { // Given - var image = new DockerImage("testcontainers", "test", "0.1.0"); + var image = new DockerImage(string.Empty, "testcontainers/test", "0.1.0"); var expected = new SortedSet { ".dockerignore", "Dockerfile", "setup/setup.sh" }; @@ -84,9 +84,9 @@ public async Task ThrowsDockerfileDirectoryDoesNotExist() public async Task BuildsDockerImage() { // Given - IImage tag1 = new DockerImage("localhost/testcontainers", Guid.NewGuid().ToString("D"), string.Empty); + IImage tag1 = new DockerImage("localhost", $"testcontainers/{Guid.NewGuid():D}", string.Empty); - IImage tag2 = new DockerImage("localhost/testcontainers", Guid.NewGuid().ToString("D"), string.Empty); + IImage tag2 = new DockerImage("localhost", $"testcontainers/{Guid.NewGuid():D}", string.Empty); var imageFromDockerfileBuilder = new ImageFromDockerfileBuilder() .WithName(tag1) @@ -106,8 +106,8 @@ await imageFromDockerfileBuilder.CreateAsync() // Then Assert.True(DockerCli.ResourceExists(DockerCli.DockerResource.Image, tag1.FullName)); Assert.True(DockerCli.ResourceExists(DockerCli.DockerResource.Image, tag2.FullName)); + Assert.NotNull(imageFromDockerfileBuilder.Registry); Assert.NotNull(imageFromDockerfileBuilder.Repository); - Assert.NotNull(imageFromDockerfileBuilder.Name); Assert.NotNull(imageFromDockerfileBuilder.Tag); Assert.NotNull(imageFromDockerfileBuilder.FullName); Assert.Null(imageFromDockerfileBuilder.GetHostname()); diff --git a/tests/Testcontainers.Tests/Unit/Images/TestcontainersImageTest.cs b/tests/Testcontainers.Tests/Unit/Images/TestcontainersImageTest.cs index 40a47743e..d8b81c914 100644 --- a/tests/Testcontainers.Tests/Unit/Images/TestcontainersImageTest.cs +++ b/tests/Testcontainers.Tests/Unit/Images/TestcontainersImageTest.cs @@ -12,7 +12,7 @@ public void ShouldThrowArgumentNullExceptionWhenInstantiateDockerImage() { Assert.Throws(() => new DockerImage((string)null)); Assert.Throws(() => new DockerImage(null, null, null)); - Assert.Throws(() => new DockerImage("fedora", null, null)); + Assert.Throws(() => new DockerImage(null, "fedora", null)); } [Fact] @@ -54,8 +54,8 @@ public void WhenImageNameGetsAssigned(DockerImageFixtureSerializable serializabl IImage dockerImage = new DockerImage(fullName); // Then + Assert.Equal(expected.Registry, dockerImage.Registry); Assert.Equal(expected.Repository, dockerImage.Repository); - Assert.Equal(expected.Name, dockerImage.Name); Assert.Equal(expected.Tag, dockerImage.Tag); Assert.Equal(expected.FullName, dockerImage.FullName); }