Skip to content

Commit

Permalink
feat: Allow MongoDb module configuration without credentials (#983)
Browse files Browse the repository at this point in the history
Co-authored-by: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com>
  • Loading branch information
the-avid-engineer and HofmeisterAn committed Sep 6, 2023
1 parent 69b7799 commit 59991ec
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 12 deletions.
46 changes: 34 additions & 12 deletions src/Testcontainers.MongoDb/MongoDbBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ private MongoDbBuilder(MongoDbConfiguration resourceConfiguration)
/// <returns>A configured instance of <see cref="MongoDbBuilder" />.</returns>
public MongoDbBuilder WithUsername(string username)
{
return Merge(DockerResourceConfiguration, new MongoDbConfiguration(username: username))
.WithEnvironment("MONGO_INITDB_ROOT_USERNAME", username);
var initDbRootUsername = username ?? string.Empty;

return Merge(DockerResourceConfiguration, new MongoDbConfiguration(username: initDbRootUsername))
.WithEnvironment("MONGO_INITDB_ROOT_USERNAME", initDbRootUsername);
}

/// <summary>
Expand All @@ -52,15 +54,22 @@ public MongoDbBuilder WithUsername(string username)
/// <returns>A configured instance of <see cref="MongoDbBuilder" />.</returns>
public MongoDbBuilder WithPassword(string password)
{
return Merge(DockerResourceConfiguration, new MongoDbConfiguration(password: password))
.WithEnvironment("MONGO_INITDB_ROOT_PASSWORD", password);
var initDbRootPassword = password ?? string.Empty;

return Merge(DockerResourceConfiguration, new MongoDbConfiguration(password: initDbRootPassword))
.WithEnvironment("MONGO_INITDB_ROOT_PASSWORD", initDbRootPassword);
}

/// <inheritdoc />
public override MongoDbContainer Build()
{
Validate();
return new MongoDbContainer(DockerResourceConfiguration, TestcontainersSettings.Logger);

// The wait strategy relies on the configuration of MongoDb. If credentials are
// provided, the log message "Waiting for connections" appears twice.
// If the user does not provide a custom waiting strategy, append the default MongoDb waiting strategy.
var mongoDbBuilder = DockerResourceConfiguration.WaitStrategies.Count() > 1 ? this : WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new WaitUntil(DockerResourceConfiguration)));
return new MongoDbContainer(mongoDbBuilder.DockerResourceConfiguration, TestcontainersSettings.Logger);
}

/// <inheritdoc />
Expand All @@ -70,22 +79,24 @@ protected override MongoDbBuilder Init()
.WithImage(MongoDbImage)
.WithPortBinding(MongoDbPort, true)
.WithUsername(DefaultUsername)
.WithPassword(DefaultPassword)
.WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new WaitUntil()));
.WithPassword(DefaultPassword);
}

/// <inheritdoc />
protected override void Validate()
{
const string message = "Missing username or password. Both must be specified for a user to be created.";

base.Validate();

_ = Guard.Argument(DockerResourceConfiguration.Username, nameof(DockerResourceConfiguration.Username))
.NotNull()
.NotEmpty();
.NotNull();

_ = Guard.Argument(DockerResourceConfiguration.Password, nameof(DockerResourceConfiguration.Password))
.NotNull()
.NotEmpty();
.NotNull();

_ = Guard.Argument(DockerResourceConfiguration, "Credentials")
.ThrowIf(argument => 1.Equals(new[] { argument.Value.Username, argument.Value.Password }.Count(string.IsNullOrEmpty)), argument => new ArgumentException(message, argument.Name));
}

/// <inheritdoc />
Expand All @@ -111,13 +122,24 @@ private sealed class WaitUntil : IWaitUntil
{
private static readonly string[] LineEndings = { "\r\n", "\n" };

private readonly int _count;

/// <summary>
/// Initializes a new instance of the <see cref="WaitUntil" /> class.
/// </summary>
/// <param name="configuration">The container configuration.</param>
public WaitUntil(MongoDbConfiguration configuration)
{
_count = string.IsNullOrEmpty(configuration.Username) && string.IsNullOrEmpty(configuration.Password) ? 1 : 2;
}

/// <inheritdoc />
public async Task<bool> UntilAsync(IContainer container)
{
var (stdout, stderr) = await container.GetLogsAsync(timestampsEnabled: false)
.ConfigureAwait(false);

return 2.Equals(Array.Empty<string>()
return _count.Equals(Array.Empty<string>()
.Concat(stdout.Split(LineEndings, StringSplitOptions.RemoveEmptyEntries))
.Concat(stderr.Split(LineEndings, StringSplitOptions.RemoveEmptyEntries))
.Count(line => line.Contains("Waiting for connections")));
Expand Down
9 changes: 9 additions & 0 deletions tests/Testcontainers.MongoDb.Tests/MongoDbContainerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ public MongoDbDefaultConfiguration()
}
}

[UsedImplicitly]
public sealed class MongoDbNoAuthConfiguration : MongoDbContainerTest
{
public MongoDbNoAuthConfiguration()
: base(new MongoDbBuilder().WithUsername(string.Empty).WithPassword(string.Empty).Build())
{
}
}

[UsedImplicitly]
public sealed class MongoDbV5Configuration : MongoDbContainerTest
{
Expand Down

0 comments on commit 59991ec

Please sign in to comment.