Skip to content

Commit 7f4091b

Browse files
CSHARP-4256: Add a guard for CSFLE tests to ensure that used mongocryptd has expected version. (mongodb#855)
1 parent 8ead437 commit 7f4091b

File tree

1 file changed

+80
-4
lines changed

1 file changed

+80
-4
lines changed

tests/MongoDB.Driver.Tests/Specifications/client-side-encryption/EncryptionTestHelper.cs

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,23 @@
1616
using System;
1717
using System.Collections;
1818
using System.Collections.Generic;
19-
using System.Collections.ObjectModel;
19+
using System.Diagnostics;
20+
using System.IO;
2021
using System.Linq;
2122
using System.Security.Cryptography.X509Certificates;
2223
using FluentAssertions;
2324
using MongoDB.Bson;
25+
using MongoDB.Driver.Core.Clusters;
2426
using MongoDB.Driver.Core.Misc;
27+
using MongoDB.Driver.Encryption;
2528

2629
namespace MongoDB.Driver.Tests.Specifications.client_side_encryption
2730
{
2831
public static class EncryptionTestHelper
2932
{
3033
private static readonly IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> __kmsProviders;
34+
private static readonly string __defaultMongocryptdPath = Environment.GetEnvironmentVariable("MONGODB_BINARIES") ?? "";
35+
private static readonly Lazy<(bool IsValid, SemanticVersion Version)> __defaultCsfleSetupState = new Lazy<(bool IsValid, SemanticVersion Version)>(IsDefaultCsfleSetupValid, isThreadSafe: true);
3136

3237
static EncryptionTestHelper()
3338
{
@@ -102,10 +107,14 @@ public static void ConfigureDefaultExtraOptions(Dictionary<string, object> extra
102107
{
103108
Ensure.IsNotNull(extraOptions, nameof(extraOptions));
104109

105-
if (!extraOptions.ContainsKey("mongocryptdSpawnPath"))
110+
if (!extraOptions.TryGetValue("mongocryptdSpawnPath", out object value))
106111
{
107-
var mongocryptdSpawnPath = Environment.GetEnvironmentVariable("MONGODB_BINARIES") ?? "";
108-
extraOptions.Add("mongocryptdSpawnPath", mongocryptdSpawnPath);
112+
extraOptions.Add("mongocryptdSpawnPath", __defaultMongocryptdPath);
113+
114+
if (!__defaultCsfleSetupState.Value.IsValid)
115+
{
116+
throw new Exception($"The configured mongocryptd version {__defaultCsfleSetupState.Value.Version} doesn't match the server version {CoreTestConfiguration.ServerVersion}.");
117+
}
109118
}
110119

111120
var mongocryptdPort = Environment.GetEnvironmentVariable("FLE_MONGOCRYPTD_PORT");
@@ -268,5 +277,72 @@ public static IReadOnlyDictionary<string, IReadOnlyDictionary<string, object>> P
268277
bool IsPlaceholder(BsonValue value) => value.IsBsonDocument && value.AsBsonDocument.Contains("$$placeholder");
269278
string GetFromEnvVariables(string kmsProvider, string key) => kmsProvidersFromEnvs[kmsProvider][key].ToString();
270279
}
280+
281+
// private methods
282+
/// <summary>
283+
/// Ensure that used mongocryptd corresponds to used server.
284+
/// </summary>
285+
private static (bool IsValid, SemanticVersion MongocryptdVersion) IsDefaultCsfleSetupValid()
286+
{
287+
var cryptSharedLibPath = CoreTestConfiguration.GetCryptSharedLibPath();
288+
if (cryptSharedLibPath != null)
289+
{
290+
var dummyNamespace = CollectionNamespace.FromFullName("db.dummy");
291+
var autoEncryptionOptions = new AutoEncryptionOptions(
292+
dummyNamespace,
293+
kmsProviders: GetKmsProviders(filter: "local"),
294+
extraOptions: new Dictionary<string, object>() { { "cryptSharedLibPath", cryptSharedLibPath } });
295+
using (var cryptClient = CryptClientCreator.CreateCryptClient(autoEncryptionOptions.ToCryptClientSettings()))
296+
{
297+
if (cryptClient.CryptSharedLibraryVersion != null)
298+
{
299+
// csfle shared library code path
300+
return (IsValid: true, MongocryptdVersion: null);
301+
}
302+
else
303+
{
304+
// we will still try using mongocryptd
305+
}
306+
}
307+
}
308+
309+
var configuredMongocryptdVersion = GetMongocryptdVersion(__defaultMongocryptdPath);
310+
if (CompareSemanticVersionsAsReleased(configuredMongocryptdVersion, CoreTestConfiguration.ServerVersion) < 0)
311+
{
312+
return (IsValid: false, MongocryptdVersion: configuredMongocryptdVersion);
313+
}
314+
315+
return (IsValid: true, MongocryptdVersion: configuredMongocryptdVersion);
316+
317+
SemanticVersion GetMongocryptdVersion(string mongocryptdPath)
318+
{
319+
mongocryptdPath = File.Exists(mongocryptdPath) ? mongocryptdPath : Path.Combine(mongocryptdPath, "mongocryptd");
320+
using (var process = new Process())
321+
{
322+
process.StartInfo.RedirectStandardOutput = true;
323+
process.StartInfo.Arguments = "--version";
324+
process.StartInfo.FileName = mongocryptdPath;
325+
process.StartInfo.CreateNoWindow = true;
326+
process.StartInfo.UseShellExecute = false;
327+
328+
if (!process.Start())
329+
{
330+
// skip it. This case can happen if no new process resource is started
331+
// (for example, if an existing process is reused)
332+
}
333+
334+
var output = process.StandardOutput.ReadToEnd();
335+
var buildInfoBody = output.Substring(output.IndexOf("Build Info") + 12 /*key length*/);
336+
return SemanticVersion.Parse(buildInfoBody);
337+
}
338+
}
339+
340+
int CompareSemanticVersionsAsReleased(SemanticVersion a, SemanticVersion b)
341+
{
342+
var aReleased = new SemanticVersion(a.Major, a.Minor, a.Patch);
343+
var bReleased = new SemanticVersion(b.Major, b.Minor, b.Patch);
344+
return aReleased.CompareTo(bReleased);
345+
}
346+
}
271347
}
272348
}

0 commit comments

Comments
 (0)