Skip to content

Commit

Permalink
Share the lifetime implementation between ContainerFixture and Contai…
Browse files Browse the repository at this point in the history
…nerTest
  • Loading branch information
0xced committed Jun 22, 2024
1 parent a9e815b commit 04f10ae
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 69 deletions.
53 changes: 3 additions & 50 deletions src/Testcontainers.Xunit/ContainerFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,61 +8,14 @@ namespace Testcontainers.Xunit;
/// <typeparam name="TBuilderEntity">The builder entity.</typeparam>
/// <typeparam name="TContainerEntity">The container entity.</typeparam>
[PublicAPI]
public class ContainerFixture<TBuilderEntity, TContainerEntity> : IAsyncLifetime
public class ContainerFixture<TBuilderEntity, TContainerEntity>(IMessageSink messageSink) : ContainerLifetime<TBuilderEntity, TContainerEntity>
where TBuilderEntity : IContainerBuilder<TBuilderEntity, TContainerEntity>, new()
where TContainerEntity : IContainer
{
private Lazy<TContainerEntity> _container;

public ContainerFixture(IMessageSink messageSink)
{
MessageSink = messageSink;
_container = new Lazy<TContainerEntity>(() =>
{
var containerBuilder = new TBuilderEntity().WithLogger(new MessageSinkLogger(MessageSink));
return Configure(containerBuilder).Build();
});
}

/// <summary>
/// The message sink used for reporting diagnostic messages.
/// </summary>
protected IMessageSink MessageSink { get; }

/// <summary>
/// The container instance.
/// </summary>
public TContainerEntity Container => _container.Value;

/// <summary>
/// Extension point to further configure the container instance.
/// </summary>
/// <example>
/// <code>
/// public class MariaDbRootUserFixture(IMessageSink messageSink) : DbContainerFixture&lt;MariaDbBuilder, MariaDbContainer&gt;(messageSink)
/// {
/// public override DbProviderFactory DbProviderFactory => MySqlConnectorFactory.Instance;
///
/// protected override MariaDbBuilder Configure(MariaDbBuilder builder)
/// {
/// return builder.WithUsername("root");
/// }
/// }
/// </code>
/// </example>
/// <param name="builder">The container builder.</param>
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
protected virtual TBuilderEntity Configure(TBuilderEntity builder) => builder;

/// <inheritdoc />
Task IAsyncLifetime.InitializeAsync() => InitializeAsync();

/// <inheritdoc cref="IAsyncLifetime.InitializeAsync()" />
protected virtual Task InitializeAsync() => Container.StartAsync();

/// <inheritdoc />
Task IAsyncLifetime.DisposeAsync() => DisposeAsync();
protected IMessageSink MessageSink { get; } = messageSink;

/// <inheritdoc cref="IAsyncLifetime.DisposeAsync()" />
protected virtual Task DisposeAsync() => Container.DisposeAsync().AsTask();
protected override ILogger Logger { get; } = new MessageSinkLogger(messageSink);
}
64 changes: 64 additions & 0 deletions src/Testcontainers.Xunit/ContainerLifetime.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
namespace Testcontainers.Xunit;

/// <summary>
/// Base class managing the lifetime of a container.
/// </summary>
/// <typeparam name="TBuilderEntity">The builder entity.</typeparam>
/// <typeparam name="TContainerEntity">The container entity.</typeparam>
public abstract class ContainerLifetime<TBuilderEntity, TContainerEntity> : IAsyncLifetime
where TBuilderEntity : IContainerBuilder<TBuilderEntity, TContainerEntity>, new()
where TContainerEntity : IContainer
{
private readonly Lazy<TContainerEntity> _container;

/// <summary>
/// The logger.
/// </summary>
protected abstract ILogger Logger { get; }

protected ContainerLifetime()
{
_container = new Lazy<TContainerEntity>(() =>
{
var containerBuilder = new TBuilderEntity().WithLogger(Logger);
return Configure(containerBuilder).Build();
});
}

/// <summary>
/// Extension point to further configure the container instance.
/// </summary>
/// <example>
/// <code>
/// public class MariaDbRootUserFixture(IMessageSink messageSink) : DbContainerFixture&lt;MariaDbBuilder, MariaDbContainer&gt;(messageSink)
/// {
/// public override DbProviderFactory DbProviderFactory =&gt; MySqlConnectorFactory.Instance;
/// <br />
/// protected override MariaDbBuilder Configure(MariaDbBuilder builder)
/// {
/// return builder.WithUsername("root");
/// }
/// }
/// </code>
/// </example>
/// <param name="builder">The container builder.</param>
/// <returns>A configured instance of <typeparamref name="TBuilderEntity" />.</returns>
protected virtual TBuilderEntity Configure(TBuilderEntity builder) => builder;

/// <summary>
/// The container instance.
/// </summary>
public TContainerEntity Container => _container.Value;

/// <inheritdoc />
Task IAsyncLifetime.InitializeAsync() => InitializeAsync();

/// <inheritdoc cref="IAsyncLifetime.InitializeAsync()" />
protected virtual Task InitializeAsync() => Container.StartAsync();

/// <inheritdoc />
Task IAsyncLifetime.DisposeAsync() => DisposeAsync();

/// <inheritdoc cref="IAsyncLifetime.DisposeAsync()" />
protected virtual Task DisposeAsync() => Container.DisposeAsync().AsTask();
}
24 changes: 5 additions & 19 deletions src/Testcontainers.Xunit/ContainerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,16 @@ namespace Testcontainers.Xunit;
/// <typeparam name="TBuilderEntity">The builder entity.</typeparam>
/// <typeparam name="TContainerEntity">The container entity.</typeparam>
[PublicAPI]
public abstract class ContainerTest<TBuilderEntity, TContainerEntity> : IAsyncLifetime
public abstract class ContainerTest<TBuilderEntity, TContainerEntity>(ITestOutputHelper testOutputHelper, Func<TBuilderEntity, TBuilderEntity> configure = null) : ContainerLifetime<TBuilderEntity, TContainerEntity>
where TBuilderEntity : IContainerBuilder<TBuilderEntity, TContainerEntity>, new()
where TContainerEntity : IContainer
{
protected ContainerTest(ITestOutputHelper testOutputHelper, Func<TBuilderEntity, TBuilderEntity> configure = null)
{
var builder = new TBuilderEntity().WithLogger(new TestOutputLogger(testOutputHelper));
Container = configure == null ? builder.Build() : configure(builder).Build();
}

/// <summary>
/// The container instance.
/// The helper used for writing messages to the test output.
/// </summary>
protected TContainerEntity Container { get; }

/// <inheritdoc />
Task IAsyncLifetime.InitializeAsync() => InitializeAsync();

/// <inheritdoc cref="IAsyncLifetime.InitializeAsync()" />
protected virtual Task InitializeAsync() => Container.StartAsync();
protected ITestOutputHelper TestOutputHelper { get; } = testOutputHelper;

/// <inheritdoc />
Task IAsyncLifetime.DisposeAsync() => DisposeAsync();
protected override ILogger Logger { get; } = new TestOutputLogger(testOutputHelper);

/// <inheritdoc cref="IAsyncLifetime.DisposeAsync()" />
protected virtual Task DisposeAsync() => Container.DisposeAsync().AsTask();
protected override TBuilderEntity Configure(TBuilderEntity builder) => configure != null ? configure(builder) : builder;
}

0 comments on commit 04f10ae

Please sign in to comment.