Skip to content

Commit 59991ec

Browse files
feat: Allow MongoDb module configuration without credentials (#983)
Co-authored-by: Andre Hofmeister <9199345+HofmeisterAn@users.noreply.github.com>
1 parent 69b7799 commit 59991ec

File tree

2 files changed

+43
-12
lines changed

2 files changed

+43
-12
lines changed

src/Testcontainers.MongoDb/MongoDbBuilder.cs

+34-12
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ private MongoDbBuilder(MongoDbConfiguration resourceConfiguration)
4141
/// <returns>A configured instance of <see cref="MongoDbBuilder" />.</returns>
4242
public MongoDbBuilder WithUsername(string username)
4343
{
44-
return Merge(DockerResourceConfiguration, new MongoDbConfiguration(username: username))
45-
.WithEnvironment("MONGO_INITDB_ROOT_USERNAME", username);
44+
var initDbRootUsername = username ?? string.Empty;
45+
46+
return Merge(DockerResourceConfiguration, new MongoDbConfiguration(username: initDbRootUsername))
47+
.WithEnvironment("MONGO_INITDB_ROOT_USERNAME", initDbRootUsername);
4648
}
4749

4850
/// <summary>
@@ -52,15 +54,22 @@ public MongoDbBuilder WithUsername(string username)
5254
/// <returns>A configured instance of <see cref="MongoDbBuilder" />.</returns>
5355
public MongoDbBuilder WithPassword(string password)
5456
{
55-
return Merge(DockerResourceConfiguration, new MongoDbConfiguration(password: password))
56-
.WithEnvironment("MONGO_INITDB_ROOT_PASSWORD", password);
57+
var initDbRootPassword = password ?? string.Empty;
58+
59+
return Merge(DockerResourceConfiguration, new MongoDbConfiguration(password: initDbRootPassword))
60+
.WithEnvironment("MONGO_INITDB_ROOT_PASSWORD", initDbRootPassword);
5761
}
5862

5963
/// <inheritdoc />
6064
public override MongoDbContainer Build()
6165
{
6266
Validate();
63-
return new MongoDbContainer(DockerResourceConfiguration, TestcontainersSettings.Logger);
67+
68+
// The wait strategy relies on the configuration of MongoDb. If credentials are
69+
// provided, the log message "Waiting for connections" appears twice.
70+
// If the user does not provide a custom waiting strategy, append the default MongoDb waiting strategy.
71+
var mongoDbBuilder = DockerResourceConfiguration.WaitStrategies.Count() > 1 ? this : WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new WaitUntil(DockerResourceConfiguration)));
72+
return new MongoDbContainer(mongoDbBuilder.DockerResourceConfiguration, TestcontainersSettings.Logger);
6473
}
6574

6675
/// <inheritdoc />
@@ -70,22 +79,24 @@ protected override MongoDbBuilder Init()
7079
.WithImage(MongoDbImage)
7180
.WithPortBinding(MongoDbPort, true)
7281
.WithUsername(DefaultUsername)
73-
.WithPassword(DefaultPassword)
74-
.WithWaitStrategy(Wait.ForUnixContainer().AddCustomWaitStrategy(new WaitUntil()));
82+
.WithPassword(DefaultPassword);
7583
}
7684

7785
/// <inheritdoc />
7886
protected override void Validate()
7987
{
88+
const string message = "Missing username or password. Both must be specified for a user to be created.";
89+
8090
base.Validate();
8191

8292
_ = Guard.Argument(DockerResourceConfiguration.Username, nameof(DockerResourceConfiguration.Username))
83-
.NotNull()
84-
.NotEmpty();
93+
.NotNull();
8594

8695
_ = Guard.Argument(DockerResourceConfiguration.Password, nameof(DockerResourceConfiguration.Password))
87-
.NotNull()
88-
.NotEmpty();
96+
.NotNull();
97+
98+
_ = Guard.Argument(DockerResourceConfiguration, "Credentials")
99+
.ThrowIf(argument => 1.Equals(new[] { argument.Value.Username, argument.Value.Password }.Count(string.IsNullOrEmpty)), argument => new ArgumentException(message, argument.Name));
89100
}
90101

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

125+
private readonly int _count;
126+
127+
/// <summary>
128+
/// Initializes a new instance of the <see cref="WaitUntil" /> class.
129+
/// </summary>
130+
/// <param name="configuration">The container configuration.</param>
131+
public WaitUntil(MongoDbConfiguration configuration)
132+
{
133+
_count = string.IsNullOrEmpty(configuration.Username) && string.IsNullOrEmpty(configuration.Password) ? 1 : 2;
134+
}
135+
114136
/// <inheritdoc />
115137
public async Task<bool> UntilAsync(IContainer container)
116138
{
117139
var (stdout, stderr) = await container.GetLogsAsync(timestampsEnabled: false)
118140
.ConfigureAwait(false);
119141

120-
return 2.Equals(Array.Empty<string>()
142+
return _count.Equals(Array.Empty<string>()
121143
.Concat(stdout.Split(LineEndings, StringSplitOptions.RemoveEmptyEntries))
122144
.Concat(stderr.Split(LineEndings, StringSplitOptions.RemoveEmptyEntries))
123145
.Count(line => line.Contains("Waiting for connections")));

tests/Testcontainers.MongoDb.Tests/MongoDbContainerTest.cs

+9
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ public MongoDbDefaultConfiguration()
5757
}
5858
}
5959

60+
[UsedImplicitly]
61+
public sealed class MongoDbNoAuthConfiguration : MongoDbContainerTest
62+
{
63+
public MongoDbNoAuthConfiguration()
64+
: base(new MongoDbBuilder().WithUsername(string.Empty).WithPassword(string.Empty).Build())
65+
{
66+
}
67+
}
68+
6069
[UsedImplicitly]
6170
public sealed class MongoDbV5Configuration : MongoDbContainerTest
6271
{

0 commit comments

Comments
 (0)