Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement prose tests checking that neither mongocryptd nor its client are created when they are not supposed to be #1113

Merged
merged 6 commits into from
May 19, 2023

Conversation

stIncMale
Copy link
Member

@stIncMale stIncMale commented May 4, 2023

Note that while JAVA-4794 adds one test, the other tests in the same section 8. Bypass Spawning mongocryptd appear to be missing in our codebase, so I also implemented them.

The "Commits" WUI view does something weird to the commit messages. The actual commit messages are something like the following, and point to the ID of the group in the spec:

There are small deviations in some tests comparing to their prose description, made to make our life better in a situation when the tests fail. I created DRIVERS-2624 with a PR suggesting to include the changes in the spec.

JAVA-4741
JAVA-4794

Comment on lines 67 to 73
--tests "*.ClientEncryption*" --tests "*.ClientSideEncryption*" \
driver-sync:test \
--tests com.mongodb.client.ClientSideEncryptionTest \
--tests com.mongodb.client.unified.ClientSideEncryptionTest \
--tests "*.ClientEncryption*" --tests "*.ClientSideEncryption*" \
driver-reactive-streams:test \
--tests com.mongodb.reactivestreams.client.ClientSideEncryptionTest \
--tests com.mongodb.reactivestreams.client.unified.ClientSideEncryptionTest \
--tests "*.ClientEncryption*" --tests "*.ClientSideEncryption*" \
driver-scala:integrationTest \
--tests org.mongodb.scala.ClientSideEncryptionTest
--tests "*.ClientEncryption*" --tests "*.ClientSideEncryption*"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change together with the assumeFalse/assumeTrue(CRYPT_SHARED_LIB_PATH_SYS_PROP_VALUE != null) checks in AbstractClientSideEncryptionNotSpawnMongocryptdTest solves the issue discussed in https://mongodb.slack.com/archives/CFPHLTRMK/p1683160528003019: some of the tests added in this PR not only do not require crypt_shared, but require the library not to be loaded, which is why they are run separately (in different process) from those that load crypt_shared (once it is loaded, it can't be unloaded).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad this worked out so easily.

@@ -163,8 +163,6 @@ Do the following before running spec tests:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced this file with the one from mongodb/specifications@33a03f2 (the latest of the spec commits in JAVA-4741 and JAVA-4794).

Comment on lines -198 to -201
String cryptSharedLibPath = System.getProperty("org.mongodb.test.crypt.shared.lib.path", "");
if (!cryptSharedLibPath.isEmpty()) {
extraOptions.put("cryptSharedLibPath", cryptSharedLibPath);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also needed to use this Java system property, so I refactored this code a bit.

Comment on lines -202 to -204
kmsProviderProperties -> kmsProviderProperties.put("key", Base64.getDecoder().decode(
"Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZ"
+ "GJkTXVyZG9uSjFk")),
Copy link
Member Author

@stIncMale stIncMale May 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also needed to use this key, so I refactored this code a bit. See UnifiedClientEncryptionHelper.

.keyVaultNamespace(KEY_VAULT_NAMESPACE.getFullName())
.extraOptions(Stream.of(
new SimpleImmutableEntry<>("cryptSharedLibPath", CRYPT_SHARED_LIB_PATH_SYS_PROP_VALUE),
new SimpleImmutableEntry<>("mongocryptdURI", format("mongodb://%s:%d/db?serverSelectionTimeoutMS=%d",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prose description does not specify serverSelectionTimeoutMS, however it speeds up the test in a situation when the test fails.

Comment on lines +122 to +134
static int findAvailableMongocryptdLoopbackPort() {
try (ServerSocket serverSocket = new ServerSocket()) {
serverSocket.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
int foundPort = serverSocket.getLocalPort();
if (foundPort != DEFAULT_MONGOCRYPTD_PORT) {
return foundPort;
} else {
return findAvailableMongocryptdLoopbackPort();
}
} catch (IOException e) {
throw new RuntimeException("Failed to find an available port", e);
}
}
Copy link
Member Author

@stIncMale stIncMale May 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could have just used serverSocket.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)) right away in ConnectionTracker.start instead of introducing the findAvailableMongocryptdLoopbackPort method. However, the same approach is not helpful for the tests in AbstractClientSideEncryptionNotSpawnMongocryptdTest. Additionally, making sure that we never use the default mongocryptd port in AbstractClientSideEncryptionNotSpawnMongocryptdTest also improve the isolation between different tests.

To avoid using different approaches, I simply use findAvailableMongocryptdLoopbackPort in both AbstractClientSideEncryptionNotCreateMongocryptdClientTest and AbstractClientSideEncryptionNotSpawnMongocryptdTest.

Comment on lines 187 to 195
private void setUpKeyVaultNamespace() {
try (MongoClient client = createMongoClient(MongoClientSettings.builder().build())) {
MongoDatabase db = client.getDatabase(KEY_VAULT_NAMESPACE.getDatabaseName());
db.drop();
db.getCollection(KEY_VAULT_NAMESPACE.getCollectionName(), BsonDocument.class)
.withWriteConcern(WriteConcern.MAJORITY)
.insertOne(EXTERNAL_KEY);
}
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prose tests do not require having any keys in the KEY_VAULT_NAMESPACE: only viaMongocryptdBypassSpawn attempts to insert an encrypted field, and that insertion is supposed to fail. However, when the driver misbehaves or tests fail (in my case, viaMongocryptdBypassSpawn was failing if viaLoadingSharedLibrary runs before it in the same process due to viaLoadingSharedLibrary loading crypt_shared), things may get too difficult to understand if the encryption is not properly set up.

Comment on lines +199 to +204
// We pick a random available `mongocryptd` port and also include it in the PID file path
// to reduce the chances of different test runs interfering with each other. The interference
// may come from the fact that once spawned, `mongocryptd` stays up and running for some time,
// which may cause failures in other runs if they use the same `mongocryptd` port / PID file.
format("--pidfilepath=bypass-spawning-mongocryptd-%d.pid", mongocryptdSocketAddress.getPort()),
format("--port=%d", mongocryptdSocketAddress.getPort())));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment in the code explains why this is done the way it is, even though the prose tests do not require anything like that.

@stIncMale
Copy link
Member Author

@jyemin Are you OK with me merging this tests-only PR based on the approval of one reviewer, or do you want to review it?

@jyemin
Copy link
Contributor

jyemin commented May 12, 2023

I'd like to take a look so please hold off on merging

Comment on lines 67 to 73
--tests "*.ClientEncryption*" --tests "*.ClientSideEncryption*" \
driver-sync:test \
--tests com.mongodb.client.ClientSideEncryptionTest \
--tests com.mongodb.client.unified.ClientSideEncryptionTest \
--tests "*.ClientEncryption*" --tests "*.ClientSideEncryption*" \
driver-reactive-streams:test \
--tests com.mongodb.reactivestreams.client.ClientSideEncryptionTest \
--tests com.mongodb.reactivestreams.client.unified.ClientSideEncryptionTest \
--tests "*.ClientEncryption*" --tests "*.ClientSideEncryption*" \
driver-scala:integrationTest \
--tests org.mongodb.scala.ClientSideEncryptionTest
--tests "*.ClientEncryption*" --tests "*.ClientSideEncryption*"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad this worked out so easily.

.evergreen/run-csfle-tests-with-mongocryptd.sh Outdated Show resolved Hide resolved
@stIncMale stIncMale requested a review from jyemin May 18, 2023 21:18
Copy link
Contributor

@jyemin jyemin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@stIncMale stIncMale merged commit 64c030f into mongodb:master May 19, 2023
42 checks passed
@stIncMale stIncMale deleted the JAVA-4741 branch May 19, 2023 00:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants