From 31d977b853807b232977147e31333b4670c32c60 Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Wed, 26 Mar 2025 10:26:57 -0400 Subject: [PATCH 1/6] add crud/findOne.json unified spec --- .../unified-test-format/crud/findOne.json | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 driver-core/src/test/resources/unified-test-format/crud/findOne.json diff --git a/driver-core/src/test/resources/unified-test-format/crud/findOne.json b/driver-core/src/test/resources/unified-test-format/crud/findOne.json new file mode 100644 index 0000000000..826c0f5dfd --- /dev/null +++ b/driver-core/src/test/resources/unified-test-format/crud/findOne.json @@ -0,0 +1,158 @@ +{ + "description": "findOne", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "find-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "find-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "tests": [ + { + "description": "FindOne with filter", + "operations": [ + { + "object": "collection0", + "name": "findOne", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectResult": { + "_id": 1, + "x": 11 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": 1 + }, + "batchSize": { + "$$exists": false + }, + "limit": 1, + "singleBatch": true + }, + "commandName": "find", + "databaseName": "find-tests" + } + } + ] + } + ] + }, + { + "description": "FindOne with filter, sort, and skip", + "operations": [ + { + "object": "collection0", + "name": "findOne", + "arguments": { + "filter": { + "_id": { + "$gt": 2 + } + }, + "sort": { + "_id": 1 + }, + "skip": 2 + }, + "expectResult": { + "_id": 5, + "x": 55 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": { + "$gt": 2 + } + }, + "sort": { + "_id": 1 + }, + "skip": 2, + "batchSize": { + "$$exists": false + }, + "limit": 1, + "singleBatch": true + }, + "commandName": "find", + "databaseName": "find-tests" + } + } + ] + } + ] + } + ] +} From 6277518848655fdabe87dfeffa53913937cd444d Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Wed, 26 Mar 2025 16:22:16 -0400 Subject: [PATCH 2/6] add comment to explain collection's findOne() method was emulated --- .../com/mongodb/client/unified/UnifiedCrudHelper.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java index 735c35dc9e..315a718eb2 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java @@ -92,6 +92,7 @@ import com.mongodb.client.result.InsertManyResult; import com.mongodb.client.result.InsertOneResult; import com.mongodb.client.result.UpdateResult; +import com.mongodb.internal.client.model.FindOptions; import com.mongodb.internal.client.model.bulk.AbstractClientDeleteOptions; import com.mongodb.internal.client.model.bulk.AbstractClientUpdateOptions; import com.mongodb.internal.client.model.bulk.ConcreteClientDeleteManyOptions; @@ -113,6 +114,7 @@ import org.bson.codecs.EncoderContext; import org.bson.codecs.ValueCodecProvider; import org.bson.codecs.configuration.CodecRegistries; +import org.bson.conversions.Bson; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -408,6 +410,13 @@ OperationResult executeFind(final BsonDocument operation) { }); } + /** + * There is no explicit {@code findOne()} method in {@link MongoCollection} class. + * Its feature was emulated by {@link FindIterable#first()}, which would close cursor on server + * by setting {@code batchSize} and {@code limit} appropriately. + * + * @see com.mongodb.internal.operation.Operations#findFirst(Bson, Class, FindOptions) + */ OperationResult executeFindOne(final BsonDocument operation) { return resultOf(() -> createFindIterable(operation).first()); } From 8a20064cf0ac9aeeb3976de86850af09b3ae8005 Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Wed, 26 Mar 2025 17:19:26 -0400 Subject: [PATCH 3/6] add language enum and skip `findOne` unified test for `driver-kotlin-coroutine` --- .../kotlin/client/coroutine/UnifiedCrudTest.kt | 2 +- .../kotlin/client/coroutine/UnifiedTest.kt | 4 ++++ .../mongodb/kotlin/client/UnifiedCrudTest.kt | 2 +- .../com/mongodb/kotlin/client/UnifiedTest.kt | 2 ++ .../unified/UnifiedReactiveStreamsTest.java | 2 +- .../client/unified/UnifiedCrudHelper.java | 4 ---- .../client/unified/UnifiedSyncTest.java | 2 +- .../mongodb/client/unified/UnifiedTest.java | 14 +++++++++++--- .../unified/UnifiedTestModifications.java | 18 +++++++++++++++--- 9 files changed, 36 insertions(+), 14 deletions(-) diff --git a/driver-kotlin-coroutine/src/integrationTest/kotlin/com/mongodb/kotlin/client/coroutine/UnifiedCrudTest.kt b/driver-kotlin-coroutine/src/integrationTest/kotlin/com/mongodb/kotlin/client/coroutine/UnifiedCrudTest.kt index 5091058573..b2836ed9f9 100644 --- a/driver-kotlin-coroutine/src/integrationTest/kotlin/com/mongodb/kotlin/client/coroutine/UnifiedCrudTest.kt +++ b/driver-kotlin-coroutine/src/integrationTest/kotlin/com/mongodb/kotlin/client/coroutine/UnifiedCrudTest.kt @@ -24,7 +24,7 @@ internal class UnifiedCrudTest() : UnifiedTest() { @JvmStatic @Throws(URISyntaxException::class, IOException::class) fun data(): Collection? { - return getTestData("unified-test-format/crud", true) + return getTestData("unified-test-format/crud", true, Language.KOTLIN) } } } diff --git a/driver-kotlin-coroutine/src/integrationTest/kotlin/com/mongodb/kotlin/client/coroutine/UnifiedTest.kt b/driver-kotlin-coroutine/src/integrationTest/kotlin/com/mongodb/kotlin/client/coroutine/UnifiedTest.kt index b027b3946c..f676f93956 100644 --- a/driver-kotlin-coroutine/src/integrationTest/kotlin/com/mongodb/kotlin/client/coroutine/UnifiedTest.kt +++ b/driver-kotlin-coroutine/src/integrationTest/kotlin/com/mongodb/kotlin/client/coroutine/UnifiedTest.kt @@ -39,4 +39,8 @@ internal abstract class UnifiedTest() : JUnifiedTest() { ): ClientEncryption { TODO("Not yet implemented - JAVA-4896") } + + override fun isReactive(): Boolean = true + + override fun getLanguage(): Language = Language.KOTLIN } diff --git a/driver-kotlin-sync/src/integrationTest/kotlin/com/mongodb/kotlin/client/UnifiedCrudTest.kt b/driver-kotlin-sync/src/integrationTest/kotlin/com/mongodb/kotlin/client/UnifiedCrudTest.kt index f030cb5464..d2c86354b1 100644 --- a/driver-kotlin-sync/src/integrationTest/kotlin/com/mongodb/kotlin/client/UnifiedCrudTest.kt +++ b/driver-kotlin-sync/src/integrationTest/kotlin/com/mongodb/kotlin/client/UnifiedCrudTest.kt @@ -24,7 +24,7 @@ internal class UnifiedCrudTest() : UnifiedTest() { @JvmStatic @Throws(URISyntaxException::class, IOException::class) fun data(): Collection? { - return getTestData("unified-test-format/crud", false) + return getTestData("unified-test-format/crud", false, Language.KOTLIN) } } } diff --git a/driver-kotlin-sync/src/integrationTest/kotlin/com/mongodb/kotlin/client/UnifiedTest.kt b/driver-kotlin-sync/src/integrationTest/kotlin/com/mongodb/kotlin/client/UnifiedTest.kt index 4f4726bbb6..7c115efc6f 100644 --- a/driver-kotlin-sync/src/integrationTest/kotlin/com/mongodb/kotlin/client/UnifiedTest.kt +++ b/driver-kotlin-sync/src/integrationTest/kotlin/com/mongodb/kotlin/client/UnifiedTest.kt @@ -39,4 +39,6 @@ internal abstract class UnifiedTest() : JUnifiedTest() { ): ClientEncryption { TODO("Not yet implemented - JAVA-4896") } + + override fun getLanguage(): Language = Language.KOTLIN } diff --git a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/unified/UnifiedReactiveStreamsTest.java b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/unified/UnifiedReactiveStreamsTest.java index 716d04a289..640d88964c 100644 --- a/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/unified/UnifiedReactiveStreamsTest.java +++ b/driver-reactive-streams/src/test/functional/com/mongodb/reactivestreams/client/unified/UnifiedReactiveStreamsTest.java @@ -101,6 +101,6 @@ protected void postCleanUp(final TestDef testDef) { @NonNull protected static Collection getTestData(final String directory) { - return getTestData(directory, true); + return getTestData(directory, true, Language.JAVA); } } diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java index 315a718eb2..0c91057aee 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedCrudHelper.java @@ -92,7 +92,6 @@ import com.mongodb.client.result.InsertManyResult; import com.mongodb.client.result.InsertOneResult; import com.mongodb.client.result.UpdateResult; -import com.mongodb.internal.client.model.FindOptions; import com.mongodb.internal.client.model.bulk.AbstractClientDeleteOptions; import com.mongodb.internal.client.model.bulk.AbstractClientUpdateOptions; import com.mongodb.internal.client.model.bulk.ConcreteClientDeleteManyOptions; @@ -114,7 +113,6 @@ import org.bson.codecs.EncoderContext; import org.bson.codecs.ValueCodecProvider; import org.bson.codecs.configuration.CodecRegistries; -import org.bson.conversions.Bson; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -414,8 +412,6 @@ OperationResult executeFind(final BsonDocument operation) { * There is no explicit {@code findOne()} method in {@link MongoCollection} class. * Its feature was emulated by {@link FindIterable#first()}, which would close cursor on server * by setting {@code batchSize} and {@code limit} appropriately. - * - * @see com.mongodb.internal.operation.Operations#findFirst(Bson, Class, FindOptions) */ OperationResult executeFindOne(final BsonDocument operation) { return resultOf(() -> createFindIterable(operation).first()); diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedSyncTest.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedSyncTest.java index e206dcc138..9fc9ef5617 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedSyncTest.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedSyncTest.java @@ -51,6 +51,6 @@ protected ClientEncryption createClientEncryption(final MongoClient keyVaultClie @NonNull protected static Collection getTestData(final String directory) { - return getTestData(directory, false); + return getTestData(directory, false, Language.JAVA); } } diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java index 6f20c0b22a..373ad0addc 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java @@ -102,6 +102,10 @@ public abstract class UnifiedTest { private static final Set PRESTART_POOL_ASYNC_WORK_MANAGER_FILE_DESCRIPTIONS = Collections.singleton( "wait queue timeout errors include details about checked out connections"); + public enum Language { + JAVA, KOTLIN, SCALA + } + public static final int RETRY_ATTEMPTS = 3; public static final int FORCE_FLAKY_ATTEMPTS = 10; private static final Set ATTEMPTED_TESTS_TO_HENCEFORTH_IGNORE = new HashSet<>(); @@ -161,7 +165,7 @@ public Entities getEntities() { } @NonNull - protected static Collection getTestData(final String directory, final boolean isReactive) { + protected static Collection getTestData(final String directory, final boolean isReactive, final Language language) { List data = new ArrayList<>(); for (BsonDocument fileDocument : getTestDocuments("/" + directory + "/")) { for (BsonValue cur : fileDocument.getArray("tests")) { @@ -169,7 +173,7 @@ protected static Collection getTestData(final String directory, final final BsonDocument testDocument = cur.asDocument(); String testDescription = testDocument.getString("description").getValue(); String fileDescription = fileDocument.getString("description").getValue(); - TestDef testDef = testDef(directory, fileDescription, testDescription, isReactive); + TestDef testDef = testDef(directory, fileDescription, testDescription, isReactive, language); applyCustomizations(testDef); boolean forceFlaky = testDef.wasAssignedModifier(Modifier.FORCE_FLAKY); @@ -240,7 +244,7 @@ public void setUp( rootContext.getAssertionContext().push(ContextElement.ofTest(definition)); ignoreExtraEvents = false; if (directoryName != null && fileDescription != null && testDescription != null) { - testDef = testDef(directoryName, fileDescription, testDescription, isReactive()); + testDef = testDef(directoryName, fileDescription, testDescription, isReactive(), getLanguage()); applyCustomizations(testDef); boolean skip = testDef.wasAssignedModifier(Modifier.SKIP); @@ -329,6 +333,10 @@ protected boolean isReactive() { return false; } + protected Language getLanguage() { + return Language.JAVA; + } + @ParameterizedTest(name = "{0}") @MethodSource("data") public void shouldPassAllOutcomes( diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java index 31b8ebb3bd..9a3a7fcded 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java @@ -143,6 +143,10 @@ public static void applyCustomizations(final TestDef def) { .test("crud", "findOneAndDelete-hint-unacknowledged", "Unacknowledged findOneAndDelete with hint string on 4.4+ server") .test("crud", "findOneAndDelete-hint-unacknowledged", "Unacknowledged findOneAndDelete with hint document on 4.4+ server"); + def.skipNoncompliant("driver-kotlin-coroutine has bug in emulating collection's findOne() method") + .when(() -> def.isReactive() && UnifiedTest.Language.KOTLIN.equals(def.getLanguage())) + .file("crud", "findOne"); + // gridfs def.skipDeprecated("contentType is deprecated in GridFS spec, and 4.x Java driver no longer supports it") @@ -256,24 +260,28 @@ public static void applyCustomizations(final TestDef def) { private UnifiedTestModifications() {} - public static TestDef testDef(final String dir, final String file, final String test, final boolean reactive) { - return new TestDef(dir, file, test, reactive); + public static TestDef testDef(final String dir, final String file, final String test, final boolean reactive, + final UnifiedTest.Language language) { + return new TestDef(dir, file, test, reactive, language); } public static final class TestDef { + private final String dir; private final String file; private final String test; private final boolean reactive; + private final UnifiedTest.Language language; private final List modifiers = new ArrayList<>(); private Function matchesThrowable; - private TestDef(final String dir, final String file, final String test, final boolean reactive) { + private TestDef(final String dir, final String file, final String test, final boolean reactive, final UnifiedTest.Language language) { this.dir = assertNotNull(dir); this.file = assertNotNull(file); this.test = assertNotNull(test); this.reactive = reactive; + this.language = language; } /** @@ -354,6 +362,10 @@ public boolean isReactive() { return reactive; } + public UnifiedTest.Language getLanguage() { + return language; + } + public boolean wasAssignedModifier(final Modifier modifier) { return this.modifiers.contains(modifier); } From 09ce4443ef760623bb033f1586764f5d043f0920 Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Tue, 1 Apr 2025 08:44:27 -0400 Subject: [PATCH 4/6] Update driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java Co-authored-by: Valentin Kovalenko --- .../com/mongodb/client/unified/UnifiedTestModifications.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java index 9a3a7fcded..ac012cec05 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java @@ -281,7 +281,7 @@ private TestDef(final String dir, final String file, final String test, final bo this.file = assertNotNull(file); this.test = assertNotNull(test); this.reactive = reactive; - this.language = language; + this.language = assertNotNull(language); } /** From 7982c75f8a12ba2a142eab74207a401327ad61cd Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Tue, 1 Apr 2025 08:52:49 -0400 Subject: [PATCH 5/6] move Language enum to better location; removed SCALA enum entry --- .../com/mongodb/client/unified/UnifiedTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java index 373ad0addc..6453f67cf2 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTest.java @@ -102,10 +102,6 @@ public abstract class UnifiedTest { private static final Set PRESTART_POOL_ASYNC_WORK_MANAGER_FILE_DESCRIPTIONS = Collections.singleton( "wait queue timeout errors include details about checked out connections"); - public enum Language { - JAVA, KOTLIN, SCALA - } - public static final int RETRY_ATTEMPTS = 3; public static final int FORCE_FLAKY_ATTEMPTS = 10; private static final Set ATTEMPTED_TESTS_TO_HENCEFORTH_IGNORE = new HashSet<>(); @@ -1120,4 +1116,8 @@ protected void ignoreExtraCommandEvents(final boolean ignoreExtraEvents) { protected void ignoreExtraEvents() { this.ignoreExtraEvents = true; } + + public enum Language { + JAVA, KOTLIN + } } From 66bf4928c3bab89261b73d5280df17793932b781 Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Tue, 1 Apr 2025 09:18:03 -0400 Subject: [PATCH 6/6] add ticket reference to UnifiedTestModifications --- .../com/mongodb/client/unified/UnifiedTestModifications.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java index ac012cec05..f908e81937 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/UnifiedTestModifications.java @@ -143,7 +143,7 @@ public static void applyCustomizations(final TestDef def) { .test("crud", "findOneAndDelete-hint-unacknowledged", "Unacknowledged findOneAndDelete with hint string on 4.4+ server") .test("crud", "findOneAndDelete-hint-unacknowledged", "Unacknowledged findOneAndDelete with hint document on 4.4+ server"); - def.skipNoncompliant("driver-kotlin-coroutine has bug in emulating collection's findOne() method") + def.skipNoncompliant("https://jira.mongodb.org/browse/JAVA-5838") .when(() -> def.isReactive() && UnifiedTest.Language.KOTLIN.equals(def.getLanguage())) .file("crud", "findOne");