Skip to content

Commit

Permalink
[testcontainers#466] #IMPLEMENT 'assemblyName: DotNet.Testcontainers;…
Browse files Browse the repository at this point in the history
… function: Image Name Substitution'
  • Loading branch information
bohlenc committed Jun 1, 2022
1 parent ba7d87b commit f4ab8e4
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 1 deletion.
9 changes: 9 additions & 0 deletions src/DotNet.Testcontainers/Builders/IImageNameSubstitutor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace DotNet.Testcontainers.Builders
{
using DotNet.Testcontainers.Images;

public interface IImageNameSubstitutor
{
IDockerImage ApplyTo(IDockerImage originalImage);
}
}
26 changes: 26 additions & 0 deletions src/DotNet.Testcontainers/Builders/ImageNameSubstitutor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace DotNet.Testcontainers.Builders
{
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Images;

public class ImageNameSubstitutor
{
public static IImageNameSubstitutor Create()
{
if (TestcontainersSettings.DockerHubImagePrefix != null)
{
return new PrefixingImageNameSubstitutor(TestcontainersSettings.DockerHubImagePrefix);
}

return new NoopImageSubstitutor();
}

public class NoopImageSubstitutor : IImageNameSubstitutor
{
public IDockerImage ApplyTo(IDockerImage originalImage)
{
return originalImage;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace DotNet.Testcontainers.Builders
{
using DotNet.Testcontainers.Images;

public class PrefixingImageNameSubstitutor : IImageNameSubstitutor
{
private readonly string prefix;

public PrefixingImageNameSubstitutor(string prefix)
{
Guard.Argument(prefix, nameof(prefix))
.NotNull();

this.prefix = prefix;
}

public IDockerImage ApplyTo(IDockerImage originalImage)
{
var imageHostedOnDockerHub = originalImage.GetHostname() == null;
if (!imageHostedOnDockerHub)
{
return originalImage;
}

return new DockerImage(originalImage.Repository.Length == 0 ? this.prefix : $"{this.prefix}/{originalImage.Repository}", originalImage.Name, originalImage.Tag);
}
}
}
4 changes: 3 additions & 1 deletion src/DotNet.Testcontainers/Builders/TestcontainersBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,12 @@ public TDockerContainer Build()
Guard.Argument(this.DockerResourceConfiguration.Image, nameof(ITestcontainersConfiguration.Image))
.NotNull();

var finalizedDockerResourceConfiguration = this.DockerResourceConfiguration.Apply(ImageNameSubstitutor.Create());

#pragma warning disable S3011

// Create container instance.
var container = (TDockerContainer)Activator.CreateInstance(typeof(TDockerContainer), BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { this.DockerResourceConfiguration, TestcontainersSettings.Logger }, null);
var container = (TDockerContainer)Activator.CreateInstance(typeof(TDockerContainer), BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { finalizedDockerResourceConfiguration, TestcontainersSettings.Logger }, null);

#pragma warning restore S3011

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace DotNet.Testcontainers.Configurations
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Builders;
using DotNet.Testcontainers.Containers;
using DotNet.Testcontainers.Images;
using DotNet.Testcontainers.Networks;
Expand Down Expand Up @@ -100,5 +101,7 @@ public interface ITestcontainersConfiguration : IDockerResourceConfiguration
/// This callback will be executed after starting the container, but before executing the wait strategies.
/// </remarks>
Func<ITestcontainersContainer, CancellationToken, Task> StartupCallback { get; }

ITestcontainersConfiguration Apply(IImageNameSubstitutor imageNameSubstitutor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace DotNet.Testcontainers.Configurations
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Builders;
using DotNet.Testcontainers.Containers;
using DotNet.Testcontainers.Images;
using DotNet.Testcontainers.Networks;
Expand Down Expand Up @@ -137,5 +138,30 @@ public TestcontainersConfiguration(

/// <inheritdoc />
public Func<ITestcontainersContainer, CancellationToken, Task> StartupCallback { get; }

public ITestcontainersConfiguration Apply(IImageNameSubstitutor imageNameSubstitutor)
{
var substitutedImageName = imageNameSubstitutor.ApplyTo(this.Image);
return new TestcontainersConfiguration(
this.Endpoint,
this.DockerRegistryAuthConfig,
substitutedImageName,
this.Name,
this.Hostname,
this.WorkingDirectory,
this.Entrypoint,
this.Command,
this.Environments,
this.Labels,
this.ExposedPorts,
this.PortBindings,
this.Mounts,
this.Networks,
this.OutputConsumer,
this.WaitStrategies,
this.StartupCallback,
this.AutoRemove,
this.Privileged);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public static class TestcontainersSettings
public static bool ResourceReaperEnabled { get; set; }
= true;

/// <summary>
/// Gets or sets a prefix to apply to images hosted on DockerHub.
/// </summary>
public static string DockerHubImagePrefix { get; set; }

/// <summary>
/// Gets or sets the logger.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ public string Hostname
}
}

/// <inheritdoc />
public string ImageName
{
get
{
return this.configuration.Image.FullName;
}
}

/// <inheritdoc />
public TestcontainersState State
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp80</s:String></wpf:ResourceDictionary>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace DotNet.Testcontainers.Tests.Unit.Builders;

using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Configurations;
using Xunit;

public class ImageNameSubstitutorTest
{
[Fact]
public void CreatesNoopImageNameSubstitutorWhenNothingElseIsConfigured()
{
var substitutor = ImageNameSubstitutor.Create();

Assert.IsType<ImageNameSubstitutor.NoopImageSubstitutor>(substitutor);
}

[Fact]
public void CreatesPrefixingImageNameSubstitutorWhenDockerHubImagePrefixIsConfigured()
{
TestcontainersSettings.DockerHubImagePrefix = "my.proxy.com";

var substitutor = ImageNameSubstitutor.Create();

Assert.IsType<PrefixingImageNameSubstitutor>(substitutor);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace DotNet.Testcontainers.Tests.Unit.Builders;

using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Images;
using Xunit;

public class PrefixingImageNameSubstitutorTest
{

[Theory]
[InlineData("my.proxy.com", "bar", "my.proxy.com/bar:latest")]
[InlineData("my.proxy.com", "bar:latest", "my.proxy.com/bar:latest")]
[InlineData("my.proxy.com", "bar:1.0.0", "my.proxy.com/bar:1.0.0")]
[InlineData("my.proxy.com", "foo/bar:1.0.0", "my.proxy.com/foo/bar:1.0.0")]
[InlineData("my.proxy.com:443", "foo/bar:1.0.0", "my.proxy.com:443/foo/bar:1.0.0")]
[InlineData("my.proxy.com", "myregistry.azurecr.io/foo/bar:1.0.0", "myregistry.azurecr.io/foo/bar:1.0.0")]
[InlineData("my.proxy.com", "myregistry.azurecr.io:443/foo/bar:1.0.0", "myregistry.azurecr.io:443/foo/bar:1.0.0")]
public void ShouldAddPrefixForDockerHubImages(string prefix, string originalImageFullName, string expectedFullName)
{
var substitutor = new PrefixingImageNameSubstitutor(prefix);

var originalImage = new DockerImage(originalImageFullName);

var actual = substitutor.ApplyTo(originalImage);

Assert.Equal(expectedFullName, actual.FullName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace DotNet.Testcontainers.Tests.Unit.Builders;

using DotNet.Testcontainers.Builders;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;
using Xunit;

public class TestcontainerBuilderTest
{
[Fact]
public void BuildAppliesDoesNotChangeImageNameWhenNoSubstitutorIsConfigured()
{
TestcontainersSettings.DockerHubImagePrefix = null;

var container = new TestcontainersBuilder<TestcontainersContainer>()
.WithImage("foo/bar:1.0.0")
.Build();

Assert.Equal("foo/bar:1.0.0", container.ImageName);
}

[Fact]
public void BuildAppliesPrexifingImageNameSubstitutorWhenDockerHubImagePrefixIsConfigured()
{
TestcontainersSettings.DockerHubImagePrefix = "my.proxy.com";

var container = new TestcontainersBuilder<TestcontainersContainer>()
.WithImage("foo/bar:1.0.0")
.Build();

Assert.Equal("my.proxy.com/foo/bar:1.0.0", container.ImageName);
}
}

0 comments on commit f4ab8e4

Please sign in to comment.