Skip to content

Commit 8f9f510

Browse files
authored
fix(MongoDb): Use db.runCommand({hello:1}) do detect readiness (#1548)
1 parent 77f4d57 commit 8f9f510

File tree

1 file changed

+38
-14
lines changed

1 file changed

+38
-14
lines changed

src/Testcontainers.MongoDb/MongoDbBuilder.cs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public MongoDbBuilder WithPassword(string password)
6565
}
6666

6767
/// <summary>
68-
/// Initialize MongoDB as a single-node replica set.
68+
/// Initializes MongoDB as a single-node replica set.
6969
/// </summary>
7070
/// <param name="replicaSetName">The replica set name.</param>
7171
/// <returns>A configured instance of <see cref="MongoDbBuilder" />.</returns>
@@ -97,7 +97,7 @@ public override MongoDbContainer Build()
9797
}
9898
else
9999
{
100-
waitUntil = new WaitInitiateReplicaSet(DockerResourceConfiguration);
100+
waitUntil = new WaitInitiateReplicaSet();
101101
}
102102

103103
// If the user does not provide a custom waiting strategy, append the default MongoDb waiting strategy.
@@ -112,7 +112,8 @@ protected override MongoDbBuilder Init()
112112
.WithImage(MongoDbImage)
113113
.WithPortBinding(MongoDbPort, true)
114114
.WithUsername(DefaultUsername)
115-
.WithPassword(DefaultPassword);
115+
.WithPassword(DefaultPassword)
116+
.WithStartupCallback(InitiateReplicaSetAsync);
116117
}
117118

118119
/// <inheritdoc />
@@ -150,6 +151,38 @@ protected override MongoDbBuilder Merge(MongoDbConfiguration oldValue, MongoDbCo
150151
return new MongoDbBuilder(new MongoDbConfiguration(oldValue, newValue));
151152
}
152153

154+
/// <summary>
155+
/// Initiates the MongoDB replica set.
156+
/// </summary>
157+
/// <param name="container">The container instance.</param>
158+
/// <param name="configuration">The container configuration.</param>
159+
/// <param name="ct">Cancellation token.</param>
160+
/// <returns>Task that completes when the replica set initiation has been executed.</returns>
161+
private async Task InitiateReplicaSetAsync(MongoDbContainer container, MongoDbConfiguration configuration, CancellationToken ct)
162+
{
163+
if (string.IsNullOrEmpty(configuration.ReplicaSetName))
164+
{
165+
return;
166+
}
167+
168+
// This is a simple workaround to use the default options, which can be configured
169+
// with custom configurations as needed.
170+
var options = new WaitStrategy();
171+
172+
var scriptContent = $"var r=rs.initiate({{_id:\"{configuration.ReplicaSetName}\",members:[{{_id:0,host:\"127.0.0.1:27017\"}}]}});quit(r.ok===1?0:1);";
173+
174+
var initiate = async () =>
175+
{
176+
var execResult = await container.ExecScriptAsync(scriptContent, ct)
177+
.ConfigureAwait(false);
178+
179+
return 0L.Equals(execResult.ExitCode);
180+
};
181+
182+
await WaitStrategy.WaitUntilAsync(initiate, options.Interval, options.Timeout, options.Retries, ct)
183+
.ConfigureAwait(false);
184+
}
185+
153186
/// <inheritdoc cref="IWaitUntil" />
154187
private sealed class WaitIndicateReadiness : IWaitUntil
155188
{
@@ -182,16 +215,7 @@ public async Task<bool> UntilAsync(IContainer container)
182215
/// <inheritdoc cref="IWaitUntil" />
183216
private sealed class WaitInitiateReplicaSet : IWaitUntil
184217
{
185-
private readonly string _scriptContent;
186-
187-
/// <summary>
188-
/// Initializes a new instance of the <see cref="WaitInitiateReplicaSet" /> class.
189-
/// </summary>
190-
/// <param name="configuration">The container configuration.</param>
191-
public WaitInitiateReplicaSet(MongoDbConfiguration configuration)
192-
{
193-
_scriptContent = $"try{{rs.status()}}catch(e){{rs.initiate({{_id:'{configuration.ReplicaSetName}',members:[{{_id:0,host:'127.0.0.1:27017'}}]}});throw e;}}";
194-
}
218+
private const string ScriptContent = "var r=db.runCommand({hello:1}).isWritablePrimary;quit(r===true?0:1);";
195219

196220
/// <inheritdoc />
197221
public Task<bool> UntilAsync(IContainer container)
@@ -202,7 +226,7 @@ public Task<bool> UntilAsync(IContainer container)
202226
/// <inheritdoc cref="IWaitUntil.UntilAsync" />
203227
private async Task<bool> UntilAsync(MongoDbContainer container)
204228
{
205-
var execResult = await container.ExecScriptAsync(_scriptContent)
229+
var execResult = await container.ExecScriptAsync(ScriptContent)
206230
.ConfigureAwait(false);
207231

208232
return 0L.Equals(execResult.ExitCode);

0 commit comments

Comments
 (0)