Skip to content

Commit

Permalink
feat(#493): Add low level modifications API for all resources (#741)
Browse files Browse the repository at this point in the history
  • Loading branch information
HofmeisterAn authored Jan 20, 2023
1 parent 872650d commit eb4a6d9
Show file tree
Hide file tree
Showing 22 changed files with 103 additions and 80 deletions.
38 changes: 23 additions & 15 deletions src/Testcontainers/Builders/AbstractBuilder`2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
/// </summary>
/// <typeparam name="TBuilderEntity">The builder entity.</typeparam>
/// <typeparam name="TResourceEntity">The resource entity.</typeparam>
/// <typeparam name="TCreateResourceEntity">The underlying Docker.DotNet resource entity.</typeparam>
/// <typeparam name="TConfigurationEntity">The configuration entity.</typeparam>
[PublicAPI]
public abstract class AbstractBuilder<TBuilderEntity, TResourceEntity, TConfigurationEntity> : IAbstractBuilder<TBuilderEntity, TResourceEntity>
where TBuilderEntity : IAbstractBuilder<TBuilderEntity, TResourceEntity>
where TConfigurationEntity : IResourceConfiguration
public abstract class AbstractBuilder<TBuilderEntity, TResourceEntity, TCreateResourceEntity, TConfigurationEntity> : IAbstractBuilder<TBuilderEntity, TResourceEntity, TCreateResourceEntity>
where TBuilderEntity : IAbstractBuilder<TBuilderEntity, TResourceEntity, TCreateResourceEntity>
where TConfigurationEntity : IResourceConfiguration<TCreateResourceEntity>
{
/// <summary>
/// Initializes a new instance of the <see cref="AbstractBuilder{TBuilderEntity, TResourceEntity, TConfigurationEntity}" /> class.
/// Initializes a new instance of the <see cref="AbstractBuilder{TBuilderEntity, TResourceEntity, TCreateResourceEntity, TConfigurationEntity}" /> class.
/// </summary>
/// <param name="dockerResourceConfiguration">The Docker resource configuration.</param>
protected AbstractBuilder(TConfigurationEntity dockerResourceConfiguration)
Expand All @@ -33,43 +34,50 @@ protected AbstractBuilder(TConfigurationEntity dockerResourceConfiguration)
/// </summary>
protected virtual TConfigurationEntity DockerResourceConfiguration { get; }

/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity}" />
/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity, TCreateResourceEntity}" />
public TBuilderEntity WithDockerEndpoint(string endpoint)
{
return this.WithDockerEndpoint(new Uri(endpoint));
}

/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity}" />
/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity, TCreateResourceEntity}" />
public TBuilderEntity WithDockerEndpoint(Uri endpoint)
{
return this.WithDockerEndpoint(new DockerEndpointAuthenticationConfiguration(endpoint));
}

/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity}" />
/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity, TCreateResourceEntity}" />
public TBuilderEntity WithDockerEndpoint(IDockerEndpointAuthenticationConfiguration dockerEndpointAuthConfig)
{
return this.Clone(new ResourceConfiguration(dockerEndpointAuthenticationConfiguration: dockerEndpointAuthConfig));
return this.Clone(new ResourceConfiguration<TCreateResourceEntity>(dockerEndpointAuthenticationConfiguration: dockerEndpointAuthConfig));
}

/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity}" />
/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity, TCreateResourceEntity}" />
public TBuilderEntity WithCleanUp(bool cleanUp)
{
return this.WithResourceReaperSessionId(TestcontainersSettings.ResourceReaperEnabled && cleanUp ? ResourceReaper.DefaultSessionId : Guid.Empty);
}

/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity}" />
/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity, TCreateResourceEntity}" />
public TBuilderEntity WithLabel(string name, string value)
{
return this.WithLabel(new Dictionary<string, string> { { name, value } });
}

/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity}" />
/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity, TCreateResourceEntity}" />
public TBuilderEntity WithLabel(IReadOnlyDictionary<string, string> labels)
{
return this.Clone(new ResourceConfiguration(labels: labels));
return this.Clone(new ResourceConfiguration<TCreateResourceEntity>(labels: labels));
}

/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity}" />
/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity, TCreateResourceEntity}" />
public TBuilderEntity WithCreateParameterModifier(Action<TCreateResourceEntity> parameterModifier)
{
var parameterModifiers = new[] { parameterModifier };
return this.Clone(new ResourceConfiguration<TCreateResourceEntity>(parameterModifiers: parameterModifiers));
}

/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TContainerEntity, TCreateResourceEntity}" />
public abstract TResourceEntity Build();

/// <summary>
Expand Down Expand Up @@ -119,7 +127,7 @@ protected virtual TBuilderEntity Init()
/// <exception cref="ArgumentException">Thrown when a mandatory Docker resource configuration is not set.</exception>
protected virtual void Validate()
{
_ = Guard.Argument(this.DockerResourceConfiguration.DockerEndpointAuthConfig, nameof(IResourceConfiguration.DockerEndpointAuthConfig))
_ = Guard.Argument(this.DockerResourceConfiguration.DockerEndpointAuthConfig, nameof(IResourceConfiguration<TCreateResourceEntity>.DockerEndpointAuthConfig))
.DockerEndpointAuthConfigIsSet();
}

Expand All @@ -128,7 +136,7 @@ protected virtual void Validate()
/// </summary>
/// <param name="resourceConfiguration">The Docker resource configuration.</param>
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
protected abstract TBuilderEntity Clone(IResourceConfiguration resourceConfiguration);
protected abstract TBuilderEntity Clone(IResourceConfiguration<TCreateResourceEntity> resourceConfiguration);

/// <summary>
/// Merges the Docker resource builder configuration.
Expand Down
9 changes: 5 additions & 4 deletions src/Testcontainers/Builders/ContainerBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace DotNet.Testcontainers.Builders
{
using Docker.DotNet.Models;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;
using JetBrains.Annotations;
Expand Down Expand Up @@ -57,15 +58,15 @@ public override IContainer Build()
}

/// <inheritdoc />
protected override ContainerBuilder Clone(IResourceConfiguration resourceConfiguration)
protected sealed override ContainerBuilder Init()
{
return this.Merge(this.DockerResourceConfiguration, new ContainerConfiguration(resourceConfiguration));
return base.Init();
}

/// <inheritdoc />
protected sealed override ContainerBuilder Init()
protected override ContainerBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
{
return base.Init();
return this.Merge(this.DockerResourceConfiguration, new ContainerConfiguration(resourceConfiguration));
}

/// <inheritdoc />
Expand Down
3 changes: 2 additions & 1 deletion src/Testcontainers/Builders/ContainerBuilder`1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
using System;
using System.Reflection;
using Docker.DotNet.Models;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Containers;
using JetBrains.Annotations;
Expand Down Expand Up @@ -71,7 +72,7 @@ protected sealed override ContainerBuilder<TContainerEntity> Init()
}

/// <inheritdoc />
protected override ContainerBuilder<TContainerEntity> Clone(IResourceConfiguration resourceConfiguration)
protected override ContainerBuilder<TContainerEntity> Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration)
{
return this.Merge(this.DockerResourceConfiguration, new ContainerConfiguration(resourceConfiguration));
}
Expand Down
13 changes: 6 additions & 7 deletions src/Testcontainers/Builders/ContainerBuilder`3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
/// <typeparam name="TContainerEntity">The resource entity.</typeparam>
/// <typeparam name="TConfigurationEntity">The configuration entity.</typeparam>
[PublicAPI]
public abstract class ContainerBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity> : AbstractBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity>, IContainerBuilder<TBuilderEntity, TContainerEntity>
public abstract class ContainerBuilder<TBuilderEntity, TContainerEntity, TConfigurationEntity> : AbstractBuilder<TBuilderEntity, TContainerEntity, CreateContainerParameters, TConfigurationEntity>, IContainerBuilder<TBuilderEntity, TContainerEntity>
where TBuilderEntity : IContainerBuilder<TBuilderEntity, TContainerEntity>
where TContainerEntity : IContainer
where TConfigurationEntity : IContainerConfiguration
Expand Down Expand Up @@ -303,8 +303,7 @@ public TBuilderEntity WithStartupCallback(Func<IContainer, CancellationToken, Ta
/// <inheritdoc cref="IContainerBuilder{TBuilderEntity, TContainerEntity}" />
public TBuilderEntity WithCreateContainerParametersModifier(Action<CreateContainerParameters> parameterModifier)
{
var parameterModifiers = new[] { parameterModifier };
return this.Clone(new ContainerConfiguration(parameterModifiers: parameterModifiers));
return this.WithCreateParameterModifier(parameterModifier);
}

public TBuilderEntity WithImage(IDockerImage image)
Expand All @@ -327,13 +326,13 @@ public TBuilderEntity WithVolumeMount(IDockerVolume volume, string destination,
return this.WithVolumeMount(new DockerVolume(volume), destination, accessMode);
}

/// <inheritdoc cref="AbstractBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TResourceEntity, TCreateResourceEntity}" />
protected override TBuilderEntity Init()
{
return base.Init().WithImagePullPolicy(PullPolicy.Missing).WithOutputConsumer(Consume.DoNotConsumeStdoutAndStderr()).WithWaitStrategy(Wait.ForUnixContainer()).WithStartupCallback((_, ct) => Task.CompletedTask);
}

/// <inheritdoc cref="AbstractBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" />
/// <inheritdoc cref="IAbstractBuilder{TBuilderEntity, TResourceEntity, TCreateResourceEntity}" />
protected override void Validate()
{
base.Validate();
Expand Down Expand Up @@ -460,13 +459,13 @@ public DockerVolume(string name)
public string Name { get; }

/// <inheritdoc cref="IVolume" />
public Task CreateAsync(CancellationToken ct)
public Task CreateAsync(CancellationToken ct = default)
{
return Task.CompletedTask;
}

/// <inheritdoc cref="IVolume" />
public Task DeleteAsync(CancellationToken ct)
public Task DeleteAsync(CancellationToken ct = default)
{
return Task.CompletedTask;
}
Expand Down
11 changes: 10 additions & 1 deletion src/Testcontainers/Builders/IAbstractBuilder`2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
/// </summary>
/// <typeparam name="TBuilderEntity">The builder entity.</typeparam>
/// <typeparam name="TResourceEntity">The resource entity.</typeparam>
/// <typeparam name="TCreateResourceEntity">The underlying Docker.DotNet resource entity.</typeparam>
[PublicAPI]
public interface IAbstractBuilder<out TBuilderEntity, out TResourceEntity>
public interface IAbstractBuilder<out TBuilderEntity, out TResourceEntity, out TCreateResourceEntity>
{
/// <summary>
/// Sets the Docker API endpoint.
Expand Down Expand Up @@ -75,6 +76,14 @@ public interface IAbstractBuilder<out TBuilderEntity, out TResourceEntity>
[PublicAPI]
TBuilderEntity WithLabel(IReadOnlyDictionary<string, string> labels);

/// <summary>
/// Allows low level modifications of the Docker.DotNet entity after the builder configuration has been applied. Multiple low level modifications will be executed in order of insertion.
/// </summary>
/// <param name="parameterModifier">The action that invokes modifying the Docker.DotNet entity instance.</param>
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
[PublicAPI]
TBuilderEntity WithCreateParameterModifier(Action<TCreateResourceEntity> parameterModifier);

/// <summary>
/// Builds an instance of <typeparamref name="TResourceEntity" /> with the given resource configuration.
/// </summary>
Expand Down
6 changes: 2 additions & 4 deletions src/Testcontainers/Builders/IContainerBuilder`2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
/// <typeparam name="TBuilderEntity">The builder entity.</typeparam>
/// <typeparam name="TContainerEntity">The resource entity.</typeparam>
[PublicAPI]
public interface IContainerBuilder<out TBuilderEntity, out TContainerEntity> : IAbstractBuilder<TBuilderEntity, TContainerEntity>
public interface IContainerBuilder<out TBuilderEntity, out TContainerEntity> : IAbstractBuilder<TBuilderEntity, TContainerEntity, CreateContainerParameters>
{
/// <summary>
/// Sets the module configuration of the container to override custom properties.
Expand Down Expand Up @@ -377,9 +377,7 @@ public interface IContainerBuilder<out TBuilderEntity, out TContainerEntity> : I
/// </remarks>
/// <param name="parameterModifier">The action that invokes modifying the <see cref="CreateContainerParameters" /> instance.</param>
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
[PublicAPI]

// TODO: Move this approach to the abstract builder, all resources benefit from a method like this.
[Obsolete("Use WithCreateParameterModifier(Action<CreateContainerParameters>) instead.")]
TBuilderEntity WithCreateContainerParametersModifier(Action<CreateContainerParameters> parameterModifier);

[Obsolete("Use WithImage(IImage) instead.")]
Expand Down
6 changes: 3 additions & 3 deletions src/Testcontainers/Builders/ImageFromDockerfileBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Docker.DotNet.Models;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Images;
using JetBrains.Annotations;
Expand All @@ -25,7 +25,7 @@
/// </code>
/// </example>
[PublicAPI]
public class ImageFromDockerfileBuilder : AbstractBuilder<ImageFromDockerfileBuilder, IFutureDockerImage, IImageFromDockerfileConfiguration>, IImageFromDockerfileBuilder<ImageFromDockerfileBuilder>
public class ImageFromDockerfileBuilder : AbstractBuilder<ImageFromDockerfileBuilder, IFutureDockerImage, ImagesCreateParameters, IImageFromDockerfileConfiguration>, IImageFromDockerfileBuilder<ImageFromDockerfileBuilder>
{
/// <summary>
/// Initializes a new instance of the <see cref="ImageFromDockerfileBuilder" /> class.
Expand Down Expand Up @@ -112,7 +112,7 @@ protected sealed override ImageFromDockerfileBuilder Init()
}

/// <inheritdoc />
protected override ImageFromDockerfileBuilder Clone(IResourceConfiguration resourceConfiguration)
protected override ImageFromDockerfileBuilder Clone(IResourceConfiguration<ImagesCreateParameters> resourceConfiguration)
{
return this.Merge(this.DockerResourceConfiguration, new ImageFromDockerfileConfiguration(resourceConfiguration));
}
Expand Down
5 changes: 3 additions & 2 deletions src/Testcontainers/Builders/NetworkBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
using System;
using System.Collections.Generic;
using Docker.DotNet.Models;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Networks;
using JetBrains.Annotations;
Expand All @@ -21,7 +22,7 @@
/// </code>
/// </example>
[PublicAPI]
public class NetworkBuilder : AbstractBuilder<NetworkBuilder, INetwork, INetworkConfiguration>, INetworkBuilder<NetworkBuilder>
public class NetworkBuilder : AbstractBuilder<NetworkBuilder, INetwork, NetworksCreateParameters, INetworkConfiguration>, INetworkBuilder<NetworkBuilder>
{
/// <summary>
/// Initializes a new instance of the <see cref="NetworkBuilder" /> class.
Expand Down Expand Up @@ -88,7 +89,7 @@ protected override void Validate()
}

/// <inheritdoc />
protected override NetworkBuilder Clone(IResourceConfiguration resourceConfiguration)
protected override NetworkBuilder Clone(IResourceConfiguration<NetworksCreateParameters> resourceConfiguration)
{
return this.Merge(this.DockerResourceConfiguration, new NetworkConfiguration(resourceConfiguration));
}
Expand Down
5 changes: 3 additions & 2 deletions src/Testcontainers/Builders/VolumeBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace DotNet.Testcontainers.Builders
{
using System;
using Docker.DotNet.Models;
using DotNet.Testcontainers.Configurations;
using DotNet.Testcontainers.Volumes;
using JetBrains.Annotations;
Expand All @@ -19,7 +20,7 @@
/// </code>
/// </example>
[PublicAPI]
public class VolumeBuilder : AbstractBuilder<VolumeBuilder, IVolume, IVolumeConfiguration>, IVolumeBuilder<VolumeBuilder>
public class VolumeBuilder : AbstractBuilder<VolumeBuilder, IVolume, VolumesCreateParameters, IVolumeConfiguration>, IVolumeBuilder<VolumeBuilder>
{
/// <summary>
/// Initializes a new instance of the <see cref="VolumeBuilder" /> class.
Expand Down Expand Up @@ -73,7 +74,7 @@ protected override void Validate()
}

/// <inheritdoc />
protected override VolumeBuilder Clone(IResourceConfiguration resourceConfiguration)
protected override VolumeBuilder Clone(IResourceConfiguration<VolumesCreateParameters> resourceConfiguration)
{
return this.Merge(this.DockerResourceConfiguration, new VolumeConfiguration(resourceConfiguration));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
/// <summary>
/// A resource configuration.
/// </summary>
/// <typeparam name="TCreateResourceEntity">The underlying Docker.DotNet resource entity.</typeparam>
[PublicAPI]
public interface IResourceConfiguration
public interface IResourceConfiguration<in TCreateResourceEntity>
{
/// <summary>
/// Gets the test session id.
Expand All @@ -24,5 +25,10 @@ public interface IResourceConfiguration
/// Gets a list of labels.
/// </summary>
IReadOnlyDictionary<string, string> Labels { get; }

/// <summary>
/// Gets a list of low level modifications of the Docker.DotNet entity.
/// </summary>
IReadOnlyList<Action<TCreateResourceEntity>> ParameterModifiers { get; }
}
}
Loading

0 comments on commit eb4a6d9

Please sign in to comment.