Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Refactor IImage properties to align with DSL #962

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Testcontainers/Builders/ContainerBuilder`3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
}

/// <inheritdoc />
Expand Down
2 changes: 1 addition & 1 deletion src/Testcontainers/Builders/ImageFromDockerfileBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public override IFutureDockerImage Build()
/// <inheritdoc />
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));
}

/// <inheritdoc />
Expand Down
24 changes: 12 additions & 12 deletions src/Testcontainers/Images/DockerImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public sealed class DockerImage : IImage
/// </summary>
/// <param name="image">The image.</param>
public DockerImage(IImage image)
: this(image.Repository, image.Name, image.Tag)
: this(image.Registry, image.Repository, image.Tag)
{
}

Expand All @@ -35,39 +35,39 @@ public DockerImage(string image)
/// <summary>
/// Initializes a new instance of the <see cref="DockerImage" /> class.
/// </summary>
/// <param name="registry">The registry.</param>
/// <param name="repository">The repository.</param>
/// <param name="name">The name.</param>
/// <param name="tag">The tag.</param>
/// <param name="hubImageNamePrefix">The Docker Hub image name prefix.</param>
/// <exception cref="ArgumentNullException">Thrown when any argument is null.</exception>
/// <example>"fedora/httpd:version1.0" where "fedora" is the repository, "httpd" the name and "version1.0" the tag.</example>
/// <example>"docker.io/fedora/httpd:version1.0" where "docker.io" is the registry, "fedora/httpd" is the repository and "version1.0" the tag.</example>
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;
}

/// <inheritdoc />
public string Repository { get; }
public string Registry { get; }

/// <inheritdoc />
public string Name { get; }
public string Repository { get; }

/// <inheritdoc />
public string Tag { get; }
Expand All @@ -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));
Expand All @@ -88,8 +88,8 @@ public string FullName
/// <inheritdoc />
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;
}
}
}
8 changes: 4 additions & 4 deletions src/Testcontainers/Images/FutureDockerImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,22 @@ public FutureDockerImage(IImageFromDockerfileConfiguration configuration, ILogge
}

/// <inheritdoc />
public string Repository
public string Registry
{
get
{
ThrowIfResourceNotFound();
return _configuration.Image.Repository;
return _configuration.Image.Registry;
}
}

/// <inheritdoc />
public string Name
public string Repository
{
get
{
ThrowIfResourceNotFound();
return _configuration.Image.Name;
return _configuration.Image.Repository;
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/Testcontainers/Images/IImage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ namespace DotNet.Testcontainers.Images
public interface IImage
{
/// <summary>
/// Gets the repository.
/// Gets the registry.
/// </summary>
[NotNull]
string Repository { get; }
string Registry { get; }

/// <summary>
/// Gets the name.
/// Gets the repository.
/// </summary>
[NotNull]
string Name { get; }
string Repository { get; }

/// <summary>
/// Gets the tag.
Expand Down
28 changes: 8 additions & 20 deletions src/Testcontainers/Images/MatchImage.cs
Original file line number Diff line number Diff line change
@@ -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(@"^((?<registry>[^\.\/\:]+(\.[^\.\/\:]*)+(\:[^\/]+)?|[^\:\/]+(\:[^\/]+)|localhost)\/)?(?<repository>[^\:\n]*)(\:(?<tag>.+)?)?$", 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);
}
}
}
26 changes: 14 additions & 12 deletions tests/Testcontainers.Tests/Fixtures/Images/DockerImageFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,22 @@ public sealed class DockerImageFixture : TheoryData<DockerImageFixtureSerializab
{
public DockerImageFixture()
{
Add(new DockerImageFixtureSerializable(new DockerImage("baz/foo", "bar", "1.0.0")), "baz/foo/bar:1.0.0");
Add(new DockerImageFixtureSerializable(new DockerImage("baz/foo", "bar", string.Empty)), "baz/foo/bar");
Add(new DockerImageFixtureSerializable(new DockerImage("baz/foo", "bar", string.Empty)), "baz/foo/bar:latest");
Add(new DockerImageFixtureSerializable(new DockerImage("foo", "bar", "1.0.0")), "foo/bar:1.0.0");
Add(new DockerImageFixtureSerializable(new DockerImage("foo", "bar", string.Empty)), "foo/bar");
Add(new DockerImageFixtureSerializable(new DockerImage("foo", "bar", string.Empty)), "foo/bar:latest");
Add(new DockerImageFixtureSerializable(new DockerImage(string.Empty, "baz/foo/bar", "1.0.0")), "baz/foo/bar:1.0.0");
Add(new DockerImageFixtureSerializable(new DockerImage(string.Empty, "baz/foo/bar", string.Empty)), "baz/foo/bar");
Add(new DockerImageFixtureSerializable(new DockerImage(string.Empty, "baz/foo/bar", string.Empty)), "baz/foo/bar:latest");
Add(new DockerImageFixtureSerializable(new DockerImage(string.Empty, "foo/bar", "1.0.0")), "foo/bar:1.0.0");
Add(new DockerImageFixtureSerializable(new DockerImage(string.Empty, "foo/bar", string.Empty)), "foo/bar");
Add(new DockerImageFixtureSerializable(new DockerImage(string.Empty, "foo/bar", string.Empty)), "foo/bar:latest");
Add(new DockerImageFixtureSerializable(new DockerImage(string.Empty, "bar", "1.0.0")), "bar:1.0.0");
Add(new DockerImageFixtureSerializable(new DockerImage(string.Empty, "bar", string.Empty)), "bar:latest");
Add(new DockerImageFixtureSerializable(new DockerImage("myregistry.azurecr.io/baz/foo", "bar", "1.0.0")), "myregistry.azurecr.io/baz/foo/bar:1.0.0");
Add(new DockerImageFixtureSerializable(new DockerImage("myregistry.azurecr.io/baz/foo", "bar", string.Empty)), "myregistry.azurecr.io/baz/foo/bar");
Add(new DockerImageFixtureSerializable(new DockerImage("myregistry.azurecr.io/baz/foo", "bar", string.Empty)), "myregistry.azurecr.io/baz/foo/bar:latest");
Add(new DockerImageFixtureSerializable(new DockerImage("fedora", "httpd", "version1.0.test")), "fedora/httpd:version1.0.test");
Add(new DockerImageFixtureSerializable(new DockerImage("fedora", "httpd", "version1.0")), "fedora/httpd:version1.0");
Add(new DockerImageFixtureSerializable(new DockerImage("myregistryhost:5000/fedora", "httpd", "version1.0")), "myregistryhost:5000/fedora/httpd:version1.0");
Add(new DockerImageFixtureSerializable(new DockerImage("myregistry.azurecr.io", "baz/foo/bar", "1.0.0")), "myregistry.azurecr.io/baz/foo/bar:1.0.0");
Add(new DockerImageFixtureSerializable(new DockerImage("myregistry.azurecr.io", "baz/foo/bar", string.Empty)), "myregistry.azurecr.io/baz/foo/bar");
Add(new DockerImageFixtureSerializable(new DockerImage("myregistry.azurecr.io", "baz/foo/bar", string.Empty)), "myregistry.azurecr.io/baz/foo/bar:latest");
Add(new DockerImageFixtureSerializable(new DockerImage(string.Empty, "fedora/httpd", "version1.0.test")), "fedora/httpd:version1.0.test");
Add(new DockerImageFixtureSerializable(new DockerImage(string.Empty, "fedora/httpd", "version1.0")), "fedora/httpd:version1.0");
Add(new DockerImageFixtureSerializable(new DockerImage("myregistryhost:5000", "fedora/httpd", "version1.0")), "myregistryhost:5000/fedora/httpd:version1.0");
Add(new DockerImageFixtureSerializable(new DockerImage("localhost", "foo/bar", string.Empty)), "localhost/foo/bar");
Add(new DockerImageFixtureSerializable(new DockerImage("localhost:5000", "foo/bar", "baz")), "localhost:5000/foo/bar:baz");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ public DockerImageFixtureSerializable(IImage image)

public void Deserialize(IXunitSerializationInfo info)
{
var repository = info.GetValue<string>("Repository");
var name = info.GetValue<string>("Name");
var tag = info.GetValue<string>("Tag");
Image = new DockerImage(repository, name, tag);
var registry = info.GetValue<string>(nameof(IImage.Registry));
var repository = info.GetValue<string>(nameof(IImage.Repository));
var tag = info.GetValue<string>(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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ await Task.CompletedTask
.ConfigureAwait(false);

// Then
Assert.Throws<InvalidOperationException>(() => image.Registry);
Assert.Throws<InvalidOperationException>(() => image.Repository);
Assert.Throws<InvalidOperationException>(() => image.Name);
Assert.Throws<InvalidOperationException>(() => image.Tag);
Assert.Throws<InvalidOperationException>(() => image.FullName);
Assert.Throws<InvalidOperationException>(() => image.GetHostname());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> { ".dockerignore", "Dockerfile", "setup/setup.sh" };

Expand Down Expand Up @@ -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)
Expand All @@ -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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public void ShouldThrowArgumentNullExceptionWhenInstantiateDockerImage()
{
Assert.Throws<ArgumentException>(() => new DockerImage((string)null));
Assert.Throws<ArgumentException>(() => new DockerImage(null, null, null));
Assert.Throws<ArgumentException>(() => new DockerImage("fedora", null, null));
Assert.Throws<ArgumentException>(() => new DockerImage(null, "fedora", null));
}

[Fact]
Expand Down Expand Up @@ -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);
}
Expand Down