From b9c4863bdb2bbd5abfa7b4653f0f0ebaf4a74cc6 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Tue, 10 Oct 2023 13:09:03 -0400 Subject: [PATCH 01/47] Version: bump 4.11.1-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ac216dda6b9..95431773403 100644 --- a/build.gradle +++ b/build.gradle @@ -74,7 +74,7 @@ configure(coreProjects) { apply plugin: 'idea' group = 'org.mongodb' - version = '4.11.0' + version = '4.11.1-SNAPSHOT' repositories { mavenLocal() From 0fb1bb432991df9fc8b3b6b914f5de8836f93dde Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Tue, 10 Oct 2023 12:41:42 -0400 Subject: [PATCH 02/47] Fix Evergreen issues * Make shell scripts executable * Remove unnecessary and sometimes harmful shell script tweaks in the pre tasks --- .evergreen/.evg.yml | 24 ------------------- ...run-atlas-search-index-management-tests.sh | 0 .evergreen/run-deployed-lambda-aws-tests.sh | 0 .evergreen/run-socks5-tests.sh | 0 4 files changed, 24 deletions(-) mode change 100644 => 100755 .evergreen/run-atlas-search-index-management-tests.sh mode change 100644 => 100755 .evergreen/run-deployed-lambda-aws-tests.sh mode change 100644 => 100755 .evergreen/run-socks5-tests.sh diff --git a/.evergreen/.evg.yml b/.evergreen/.evg.yml index dc843379d2d..bab2690ff82 100644 --- a/.evergreen/.evg.yml +++ b/.evergreen/.evg.yml @@ -856,25 +856,6 @@ functions: perl -p -i -e "s|ABSOLUTE_PATH_REPLACEMENT_TOKEN|${DRIVERS_TOOLS}|g" $filename done - "windows fix": - - command: shell.exec - params: - script: | - ${PREPARE_SHELL} - for i in $(find ${DRIVERS_TOOLS}/.evergreen ${PROJECT_DIRECTORY}/.evergreen -name \*.sh); do - cat $i | tr -d '\r' > $i.new - mv $i.new $i - done - - "make files executable": - - command: shell.exec - params: - script: | - ${PREPARE_SHELL} - for i in $(find ${DRIVERS_TOOLS}/.evergreen ${PROJECT_DIRECTORY}/.evergreen -name \*.sh); do - chmod +x $i - done - "run perf tests": - command: shell.exec type: test @@ -894,9 +875,7 @@ functions: pre: - func: "fetch source" - func: "prepare resources" - - func: "windows fix" - func: "fix absolute paths" - - func: "make files executable" post: - func: "upload mo artifacts" @@ -1864,7 +1843,6 @@ task_groups: setup_group: - func: fetch source - func: prepare resources - - func: make files executable - command: subprocess.exec params: working_dir: src @@ -1894,7 +1872,6 @@ task_groups: - func: fetch source - func: prepare resources - func: fix absolute paths - - func: make files executable - command: shell.exec params: shell: "bash" @@ -1930,7 +1907,6 @@ task_groups: - func: fetch source - func: prepare resources - func: fix absolute paths - - func: make files executable - command: shell.exec params: shell: "bash" diff --git a/.evergreen/run-atlas-search-index-management-tests.sh b/.evergreen/run-atlas-search-index-management-tests.sh old mode 100644 new mode 100755 diff --git a/.evergreen/run-deployed-lambda-aws-tests.sh b/.evergreen/run-deployed-lambda-aws-tests.sh old mode 100644 new mode 100755 diff --git a/.evergreen/run-socks5-tests.sh b/.evergreen/run-socks5-tests.sh old mode 100644 new mode 100755 From 81ad6a1c247bac3298ad4de60c564435db01ef06 Mon Sep 17 00:00:00 2001 From: Gordon Wang Date: Mon, 23 Oct 2023 22:46:55 +1100 Subject: [PATCH 03/47] Support decoding nulls for non-primitive fields in Java records (#1223) JAVA-5203 --- .../org/bson/codecs/record/RecordCodec.java | 8 +++++ .../bson/codecs/record/RecordCodecTest.java | 32 +++++++++++++++++++ .../samples/TestRecordWithNullableField.java | 23 +++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 bson-record-codec/src/test/unit/org/bson/codecs/record/samples/TestRecordWithNullableField.java diff --git a/bson-record-codec/src/main/org/bson/codecs/record/RecordCodec.java b/bson-record-codec/src/main/org/bson/codecs/record/RecordCodec.java index 8a304760f31..5bce0560233 100644 --- a/bson-record-codec/src/main/org/bson/codecs/record/RecordCodec.java +++ b/bson-record-codec/src/main/org/bson/codecs/record/RecordCodec.java @@ -16,6 +16,7 @@ package org.bson.codecs.record; +import org.bson.BsonInvalidOperationException; import org.bson.BsonReader; import org.bson.BsonType; import org.bson.BsonWriter; @@ -62,6 +63,7 @@ private static final class ComponentModel { private final Codec codec; private final int index; private final String fieldName; + private final boolean isNullable; private ComponentModel(final List typeParameters, final RecordComponent component, final CodecRegistry codecRegistry, final int index) { @@ -70,6 +72,7 @@ private ComponentModel(final List typeParameters, final RecordComponent co this.codec = computeCodec(typeParameters, component, codecRegistry); this.index = index; this.fieldName = computeFieldName(component); + this.isNullable = !component.getType().isPrimitive(); } String getComponentName() { @@ -275,6 +278,11 @@ public T decode(final BsonReader reader, final DecoderContext decoderContext) { if (LOGGER.isTraceEnabled()) { LOGGER.trace(format("Found property not present in the ClassModel: %s", fieldName)); } + } else if (reader.getCurrentBsonType() == BsonType.NULL) { + if (!componentModel.isNullable) { + throw new BsonInvalidOperationException(format("Null value on primitive field: %s", componentModel.fieldName)); + } + reader.readNull(); } else { constructorArguments[componentModel.index] = decoderContext.decodeWithChildContext(componentModel.codec, reader); } diff --git a/bson-record-codec/src/test/unit/org/bson/codecs/record/RecordCodecTest.java b/bson-record-codec/src/test/unit/org/bson/codecs/record/RecordCodecTest.java index 606bc68e59a..636554443fd 100644 --- a/bson-record-codec/src/test/unit/org/bson/codecs/record/RecordCodecTest.java +++ b/bson-record-codec/src/test/unit/org/bson/codecs/record/RecordCodecTest.java @@ -22,6 +22,8 @@ import org.bson.BsonDocumentWriter; import org.bson.BsonDouble; import org.bson.BsonInt32; +import org.bson.BsonInvalidOperationException; +import org.bson.BsonNull; import org.bson.BsonObjectId; import org.bson.BsonString; import org.bson.codecs.DecoderContext; @@ -49,6 +51,7 @@ import org.bson.codecs.record.samples.TestRecordWithMapOfRecords; import org.bson.codecs.record.samples.TestRecordWithNestedParameterized; import org.bson.codecs.record.samples.TestRecordWithNestedParameterizedRecord; +import org.bson.codecs.record.samples.TestRecordWithNullableField; import org.bson.codecs.record.samples.TestRecordWithParameterizedRecord; import org.bson.codecs.record.samples.TestRecordWithPojoAnnotations; import org.bson.codecs.record.samples.TestSelfReferentialHolderRecord; @@ -325,6 +328,35 @@ public void testRecordWithNulls() { assertEquals(testRecord, decoded); } + @Test + public void testRecordWithStoredNulls() { + var codec = createRecordCodec(TestRecordWithNullableField.class, Bson.DEFAULT_CODEC_REGISTRY); + var identifier = new ObjectId(); + var testRecord = new TestRecordWithNullableField(identifier, null, 42); + + var document = new BsonDocument("_id", new BsonObjectId(identifier)) + .append("name", new BsonNull()) + .append("age", new BsonInt32(42)); + + // when + var decoded = codec.decode(new BsonDocumentReader(document), DecoderContext.builder().build()); + + // then + assertEquals(testRecord, decoded); + } + + @Test + public void testExceptionsWithStoredNullsOnPrimitiveField() { + var codec = createRecordCodec(TestRecordWithNullableField.class, Bson.DEFAULT_CODEC_REGISTRY); + + var document = new BsonDocument("_id", new BsonObjectId(new ObjectId())) + .append("name", new BsonString("Felix")) + .append("age", new BsonNull()); + + assertThrows(BsonInvalidOperationException.class, () -> + codec.decode(new BsonDocumentReader(document), DecoderContext.builder().build())); + } + @Test public void testRecordWithExtraData() { var codec = createRecordCodec(TestRecordWithDeprecatedAnnotations.class, Bson.DEFAULT_CODEC_REGISTRY); diff --git a/bson-record-codec/src/test/unit/org/bson/codecs/record/samples/TestRecordWithNullableField.java b/bson-record-codec/src/test/unit/org/bson/codecs/record/samples/TestRecordWithNullableField.java new file mode 100644 index 00000000000..f2329c8170e --- /dev/null +++ b/bson-record-codec/src/test/unit/org/bson/codecs/record/samples/TestRecordWithNullableField.java @@ -0,0 +1,23 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bson.codecs.record.samples; + +import org.bson.codecs.pojo.annotations.BsonId; +import org.bson.types.ObjectId; + +public record TestRecordWithNullableField(@BsonId ObjectId id, String name, int age) { +} From d2cd51ec268ab7a6681f79dd030075b746e1613e Mon Sep 17 00:00:00 2001 From: Viacheslav Babanin Date: Fri, 27 Oct 2023 12:12:29 -0700 Subject: [PATCH 04/47] Add explicit automatic module name configuration. (#1236) Original PR (#1232) JAVA-5213 JAVA-5202 --- bson-kotlin/build.gradle.kts | 2 ++ bson-kotlinx/build.gradle.kts | 2 ++ bson-scala/build.gradle | 11 +++++++---- bson/build.gradle | 5 ++++- driver-kotlin-coroutine/build.gradle.kts | 2 ++ driver-kotlin-sync/build.gradle.kts | 2 ++ driver-scala/build.gradle | 2 +- gradle/publish.gradle | 1 - 8 files changed, 20 insertions(+), 7 deletions(-) diff --git a/bson-kotlin/build.gradle.kts b/bson-kotlin/build.gradle.kts index ee9358c0c72..3840b3169cf 100644 --- a/bson-kotlin/build.gradle.kts +++ b/bson-kotlin/build.gradle.kts @@ -148,3 +148,5 @@ tasks.javadocJar.configure { // Sources publishing configuration // =========================== tasks.sourcesJar { from(project.sourceSets.main.map { it.kotlin }) } + +afterEvaluate { tasks.jar { manifest { attributes["Automatic-Module-Name"] = "org.mongodb.bson.kotlin" } } } diff --git a/bson-kotlinx/build.gradle.kts b/bson-kotlinx/build.gradle.kts index 278c9988aa9..bb9dd42e10b 100644 --- a/bson-kotlinx/build.gradle.kts +++ b/bson-kotlinx/build.gradle.kts @@ -152,3 +152,5 @@ tasks.javadocJar.configure { // Sources publishing configuration // =========================== tasks.sourcesJar { from(project.sourceSets.main.map { it.kotlin }) } + +afterEvaluate { tasks.jar { manifest { attributes["Automatic-Module-Name"] = "org.mongodb.bson.kotlinx" } } } diff --git a/bson-scala/build.gradle b/bson-scala/build.gradle index e2c48a87d77..6606dec5a89 100644 --- a/bson-scala/build.gradle +++ b/bson-scala/build.gradle @@ -58,7 +58,10 @@ test { maxParallelForks = 1 } -jar.manifest.attributes['Import-Package'] = [ - '!scala.*', - '*' -].join(',') +afterEvaluate { + jar.manifest.attributes['Automatic-Module-Name'] = 'org.mongodb.bson.scala' + jar.manifest.attributes['Import-Package'] = [ + '!scala.*', + '*' + ].join(',') +} diff --git a/bson/build.gradle b/bson/build.gradle index 005c1f92411..d2b2ed3ba0e 100644 --- a/bson/build.gradle +++ b/bson/build.gradle @@ -22,4 +22,7 @@ ext { pomURL = 'https://bsonspec.org/' } -jar.manifest.attributes['Import-Package'] = 'org.slf4j.*;resolution:=optional' +afterEvaluate { + jar.manifest.attributes['Automatic-Module-Name'] = 'org.mongodb.bson' + jar.manifest.attributes['Import-Package'] = 'org.slf4j.*;resolution:=optional' +} diff --git a/driver-kotlin-coroutine/build.gradle.kts b/driver-kotlin-coroutine/build.gradle.kts index a7958fc2f4b..1467c832abe 100644 --- a/driver-kotlin-coroutine/build.gradle.kts +++ b/driver-kotlin-coroutine/build.gradle.kts @@ -193,3 +193,5 @@ tasks.javadocJar.configure { // Sources publishing configuration // =========================== tasks.sourcesJar { from(project.sourceSets.main.map { it.kotlin }) } + +afterEvaluate { tasks.jar { manifest { attributes["Automatic-Module-Name"] = "org.mongodb.driver.kotlin.coroutine" } } } diff --git a/driver-kotlin-sync/build.gradle.kts b/driver-kotlin-sync/build.gradle.kts index f9aafc091cf..05b20b4803b 100644 --- a/driver-kotlin-sync/build.gradle.kts +++ b/driver-kotlin-sync/build.gradle.kts @@ -188,3 +188,5 @@ tasks.javadocJar.configure { // Sources publishing configuration // =========================== tasks.sourcesJar { from(project.sourceSets.main.map { it.kotlin }) } + +afterEvaluate { tasks.jar { manifest { attributes["Automatic-Module-Name"] = "org.mongodb.driver.kotlin.sync" } } } diff --git a/driver-scala/build.gradle b/driver-scala/build.gradle index 0c721d6d1d9..f9852968f05 100644 --- a/driver-scala/build.gradle +++ b/driver-scala/build.gradle @@ -117,7 +117,7 @@ ext { } afterEvaluate { - jar.manifest.attributes['Automatic-Module-Name'] = 'org.mongodb.scala.mongo-scala-driver' + jar.manifest.attributes['Automatic-Module-Name'] = 'org.mongodb.driver.scala' jar.manifest.attributes['Import-Package'] = [ '!scala.*', '*' diff --git a/gradle/publish.gradle b/gradle/publish.gradle index 561e76957a5..2047ef26800 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -60,7 +60,6 @@ ext { configureJarManifestAttributes = { project -> { -> manifest.attributes['-exportcontents'] = "*;-noimport:=true" - manifest.attributes['Automatic-Module-Name'] = project.group + '.' + project.archivesBaseName manifest.attributes['Build-Version'] = project.gitVersion manifest.attributes['Bundle-Version'] = project.version manifest.attributes['Bundle-Name'] = project.archivesBaseName From db66a7cf59f5709dacd7d18abd3105396c5efe10 Mon Sep 17 00:00:00 2001 From: Viacheslav Babanin Date: Fri, 27 Oct 2023 16:42:36 -0700 Subject: [PATCH 05/47] Update logger name to align with naming conventions (#1237) Original PR mongodb#1233. JAVA-5210 --- .../com/mongodb/internal/connection/DefaultClusterFactory.java | 2 +- .../mongodb/internal/connection/DefaultClusterFactoryTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterFactory.java b/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterFactory.java index 431df80c698..ee6b9449a2b 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterFactory.java +++ b/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterFactory.java @@ -58,7 +58,7 @@ */ @SuppressWarnings("deprecation") public final class DefaultClusterFactory { - private static final Logger LOGGER = Loggers.getLogger("DefaultClusterFactory"); + private static final Logger LOGGER = Loggers.getLogger("client"); public Cluster createCluster(final ClusterSettings originalClusterSettings, final ServerSettings originalServerSettings, final ConnectionPoolSettings connectionPoolSettings, diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultClusterFactoryTest.java b/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultClusterFactoryTest.java index 2e6190a4be8..8ecec2c7494 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultClusterFactoryTest.java +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultClusterFactoryTest.java @@ -44,7 +44,7 @@ class DefaultClusterFactoryTest { "You appear to be connected to a DocumentDB cluster. For more information regarding " + "feature compatibility and support please visit https://www.mongodb.com/supportability/documentdb"; - private static final Logger LOGGER = (Logger) LoggerFactory.getLogger("org.mongodb.driver.DefaultClusterFactory"); + private static final Logger LOGGER = (Logger) LoggerFactory.getLogger("org.mongodb.driver.client"); private static final MemoryAppender MEMORY_APPENDER = new MemoryAppender(); @BeforeAll From 5409610b5d55d08b7e664239cc847d42c937b9fc Mon Sep 17 00:00:00 2001 From: Viacheslav Babanin Date: Tue, 7 Nov 2023 11:21:11 -0800 Subject: [PATCH 06/47] Remove write and read concern from Atlas Search Index commands. (#1241) JAVA-5233 --- .../AbstractWriteSearchIndexOperation.java | 10 +----- .../CreateSearchIndexesOperation.java | 11 ++---- .../operation/DropSearchIndexOperation.java | 11 ++---- .../internal/operation/Operations.java | 7 ++-- .../UpdateSearchIndexesOperation.java | 12 ++----- .../client/internal/MongoCollectionImpl.java | 5 ++- .../ListSearchIndexesIterableImpl.java | 7 ++-- .../client/internal/MongoCollectionImpl.java | 2 +- ...ctAtlasSearchIndexManagementProseTest.java | 35 +++++++++++++++++-- 9 files changed, 53 insertions(+), 47 deletions(-) diff --git a/driver-core/src/main/com/mongodb/internal/operation/AbstractWriteSearchIndexOperation.java b/driver-core/src/main/com/mongodb/internal/operation/AbstractWriteSearchIndexOperation.java index 83fbd97081f..82da3fc7646 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/AbstractWriteSearchIndexOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/AbstractWriteSearchIndexOperation.java @@ -19,7 +19,6 @@ import com.mongodb.MongoCommandException; import com.mongodb.MongoNamespace; -import com.mongodb.WriteConcern; import com.mongodb.internal.async.SingleResultCallback; import com.mongodb.internal.binding.AsyncWriteBinding; import com.mongodb.internal.binding.WriteBinding; @@ -40,12 +39,9 @@ */ abstract class AbstractWriteSearchIndexOperation implements AsyncWriteOperation, WriteOperation { private final MongoNamespace namespace; - private final WriteConcern writeConcern; - AbstractWriteSearchIndexOperation(final MongoNamespace mongoNamespace, - final WriteConcern writeConcern) { + AbstractWriteSearchIndexOperation(final MongoNamespace mongoNamespace) { this.namespace = mongoNamespace; - this.writeConcern = writeConcern; } @Override @@ -101,8 +97,4 @@ void swallowOrThrow(@Nullable final E mongoExecutionExcept MongoNamespace getNamespace() { return namespace; } - - WriteConcern getWriteConcern() { - return writeConcern; - } } diff --git a/driver-core/src/main/com/mongodb/internal/operation/CreateSearchIndexesOperation.java b/driver-core/src/main/com/mongodb/internal/operation/CreateSearchIndexesOperation.java index 0832668a85a..1a44d887586 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/CreateSearchIndexesOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/CreateSearchIndexesOperation.java @@ -17,7 +17,6 @@ package com.mongodb.internal.operation; import com.mongodb.MongoNamespace; -import com.mongodb.WriteConcern; import org.bson.BsonArray; import org.bson.BsonDocument; import org.bson.BsonString; @@ -26,7 +25,6 @@ import java.util.stream.Collectors; import static com.mongodb.assertions.Assertions.assertNotNull; -import static com.mongodb.internal.operation.WriteConcernHelper.appendWriteConcernToCommand; /** * An operation that creates one or more Atlas Search indexes. @@ -37,9 +35,8 @@ final class CreateSearchIndexesOperation extends AbstractWriteSearchIndexOperati private static final String COMMAND_NAME = "createSearchIndexes"; private final List indexRequests; - CreateSearchIndexesOperation(final MongoNamespace namespace, final List indexRequests, - final WriteConcern writeConcern) { - super(namespace, writeConcern); + CreateSearchIndexesOperation(final MongoNamespace namespace, final List indexRequests) { + super(namespace); this.indexRequests = assertNotNull(indexRequests); } @@ -61,9 +58,7 @@ private static BsonDocument convert(final SearchIndexRequest request) { @Override BsonDocument buildCommand() { - BsonDocument command = new BsonDocument(COMMAND_NAME, new BsonString(getNamespace().getCollectionName())) + return new BsonDocument(COMMAND_NAME, new BsonString(getNamespace().getCollectionName())) .append("indexes", convert(indexRequests)); - appendWriteConcernToCommand(getWriteConcern(), command); - return command; } } diff --git a/driver-core/src/main/com/mongodb/internal/operation/DropSearchIndexOperation.java b/driver-core/src/main/com/mongodb/internal/operation/DropSearchIndexOperation.java index 422af56b55b..657dedca942 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/DropSearchIndexOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/DropSearchIndexOperation.java @@ -17,13 +17,11 @@ package com.mongodb.internal.operation; import com.mongodb.MongoNamespace; -import com.mongodb.WriteConcern; import com.mongodb.lang.Nullable; import org.bson.BsonDocument; import org.bson.BsonString; import static com.mongodb.internal.operation.CommandOperationHelper.isNamespaceError; -import static com.mongodb.internal.operation.WriteConcernHelper.appendWriteConcernToCommand; /** * An operation that drops an Alas Search index. @@ -34,9 +32,8 @@ final class DropSearchIndexOperation extends AbstractWriteSearchIndexOperation { private static final String COMMAND_NAME = "dropSearchIndex"; private final String indexName; - DropSearchIndexOperation(final MongoNamespace namespace, final String indexName, - final WriteConcern writeConcern) { - super(namespace, writeConcern); + DropSearchIndexOperation(final MongoNamespace namespace, final String indexName) { + super(namespace); this.indexName = indexName; } @@ -49,9 +46,7 @@ void swallowOrThrow(@Nullable final E mongoExecutionExcept @Override BsonDocument buildCommand() { - BsonDocument command = new BsonDocument(COMMAND_NAME, new BsonString(getNamespace().getCollectionName())) + return new BsonDocument(COMMAND_NAME, new BsonString(getNamespace().getCollectionName())) .append("name", new BsonString(indexName)); - appendWriteConcernToCommand(getWriteConcern(), command); - return command; } } diff --git a/driver-core/src/main/com/mongodb/internal/operation/Operations.java b/driver-core/src/main/com/mongodb/internal/operation/Operations.java index f0f6e72b680..ed84e9b2e72 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/Operations.java +++ b/driver-core/src/main/com/mongodb/internal/operation/Operations.java @@ -651,20 +651,19 @@ CreateSearchIndexesOperation createSearchIndexes(final List in .map(this::createSearchIndexRequest) .collect(Collectors.toList()); - return new CreateSearchIndexesOperation(assertNotNull(namespace), indexRequests, writeConcern); + return new CreateSearchIndexesOperation(assertNotNull(namespace), indexRequests); } UpdateSearchIndexesOperation updateSearchIndex(final String indexName, final Bson definition) { BsonDocument definitionDocument = assertNotNull(toBsonDocument(definition)); SearchIndexRequest searchIndexRequest = new SearchIndexRequest(definitionDocument, indexName); - return new UpdateSearchIndexesOperation(assertNotNull(namespace), searchIndexRequest, - writeConcern); + return new UpdateSearchIndexesOperation(assertNotNull(namespace), searchIndexRequest); } DropSearchIndexOperation dropSearchIndex(final String indexName) { - return new DropSearchIndexOperation(assertNotNull(namespace), indexName, writeConcern); + return new DropSearchIndexOperation(assertNotNull(namespace), indexName); } diff --git a/driver-core/src/main/com/mongodb/internal/operation/UpdateSearchIndexesOperation.java b/driver-core/src/main/com/mongodb/internal/operation/UpdateSearchIndexesOperation.java index 72402a0d22e..7bd33730680 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/UpdateSearchIndexesOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/UpdateSearchIndexesOperation.java @@ -17,12 +17,9 @@ package com.mongodb.internal.operation; import com.mongodb.MongoNamespace; -import com.mongodb.WriteConcern; import org.bson.BsonDocument; import org.bson.BsonString; -import static com.mongodb.internal.operation.WriteConcernHelper.appendWriteConcernToCommand; - /** * An operation that updates an Atlas Search index. * @@ -32,19 +29,16 @@ final class UpdateSearchIndexesOperation extends AbstractWriteSearchIndexOperati private static final String COMMAND_NAME = "updateSearchIndex"; private final SearchIndexRequest request; - UpdateSearchIndexesOperation(final MongoNamespace namespace, final SearchIndexRequest request, - final WriteConcern writeConcern) { - super(namespace, writeConcern); + UpdateSearchIndexesOperation(final MongoNamespace namespace, final SearchIndexRequest request) { + super(namespace); this.request = request; } @Override BsonDocument buildCommand() { - BsonDocument command = new BsonDocument(COMMAND_NAME, new BsonString(getNamespace().getCollectionName())) + return new BsonDocument(COMMAND_NAME, new BsonString(getNamespace().getCollectionName())) .append("name", new BsonString(request.getIndexName())) .append("definition", request.getDefinition()); - appendWriteConcernToCommand(getWriteConcern(), command); - return command; } } diff --git a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/MongoCollectionImpl.java b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/MongoCollectionImpl.java index 953b45ac9ac..d9fa18c6a54 100644 --- a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/MongoCollectionImpl.java +++ b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/MongoCollectionImpl.java @@ -694,7 +694,10 @@ public ListSearchIndexesPublisher listSearchIndexes() { @Override public ListSearchIndexesPublisher listSearchIndexes(final Class resultClass) { notNull("resultClass", resultClass); - return new ListSearchIndexesPublisherImpl<>(mongoOperationPublisher.withDocumentClass(resultClass)); + + return new ListSearchIndexesPublisherImpl<>(mongoOperationPublisher + .withReadConcern(ReadConcern.DEFAULT) + .withDocumentClass(resultClass)); } @Override diff --git a/driver-sync/src/main/com/mongodb/client/internal/ListSearchIndexesIterableImpl.java b/driver-sync/src/main/com/mongodb/client/internal/ListSearchIndexesIterableImpl.java index fc949859530..0ffc9cea7a5 100644 --- a/driver-sync/src/main/com/mongodb/client/internal/ListSearchIndexesIterableImpl.java +++ b/driver-sync/src/main/com/mongodb/client/internal/ListSearchIndexesIterableImpl.java @@ -53,10 +53,9 @@ final class ListSearchIndexesIterableImpl extends MongoIterableImpl resultClass, - final CodecRegistry codecRegistry, final ReadPreference readPreference, - final boolean retryReads) { - super(null, executor, readConcern, readPreference, retryReads); + final Class resultClass, final CodecRegistry codecRegistry, + final ReadPreference readPreference, final boolean retryReads) { + super(null, executor, ReadConcern.DEFAULT, readPreference, retryReads); this.resultClass = resultClass; this.operations = new SyncOperations<>(namespace, BsonDocument.class, readPreference, codecRegistry, retryReads); diff --git a/driver-sync/src/main/com/mongodb/client/internal/MongoCollectionImpl.java b/driver-sync/src/main/com/mongodb/client/internal/MongoCollectionImpl.java index 98ed5ec334f..2d9e6cf42e8 100755 --- a/driver-sync/src/main/com/mongodb/client/internal/MongoCollectionImpl.java +++ b/driver-sync/src/main/com/mongodb/client/internal/MongoCollectionImpl.java @@ -947,7 +947,7 @@ private ListIndexesIterable createListIndexesIterable(@Nullab } private ListSearchIndexesIterable createListSearchIndexesIterable(final Class resultClass) { - return new ListSearchIndexesIterableImpl<>(getNamespace(), executor, readConcern, + return new ListSearchIndexesIterableImpl<>(getNamespace(), executor, resultClass, codecRegistry, readPreference, retryReads); } diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractAtlasSearchIndexManagementProseTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractAtlasSearchIndexManagementProseTest.java index 47a0c5f3d45..fd7bc428576 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/AbstractAtlasSearchIndexManagementProseTest.java +++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractAtlasSearchIndexManagementProseTest.java @@ -17,7 +17,12 @@ package com.mongodb.client; import com.mongodb.MongoClientSettings; +import com.mongodb.ReadConcern; +import com.mongodb.WriteConcern; import com.mongodb.client.model.SearchIndexModel; +import com.mongodb.event.CommandListener; +import com.mongodb.event.CommandStartedEvent; +import org.bson.BsonDocument; import org.bson.Document; import org.bson.conversions.Bson; import org.junit.jupiter.api.AfterEach; @@ -38,7 +43,9 @@ import java.util.stream.StreamSupport; import static com.mongodb.ClusterFixture.serverVersionAtLeast; +import static com.mongodb.assertions.Assertions.assertFalse; import static com.mongodb.client.Fixture.getMongoClientSettings; +import static com.mongodb.client.Fixture.getMongoClientSettingsBuilder; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; @@ -74,8 +81,8 @@ public abstract class AbstractAtlasSearchIndexManagementProseTest { protected abstract MongoClient createMongoClient(MongoClientSettings settings); protected AbstractAtlasSearchIndexManagementProseTest() { - Assumptions.assumeTrue(serverVersionAtLeast(6, 0)); - Assumptions.assumeTrue(hasAtlasSearchIndexHelperEnabled(), "Atlas Search Index tests are disabled"); //TODO enable by flag + Assumptions.assumeTrue(serverVersionAtLeast(6, 0)); + Assumptions.assumeTrue(hasAtlasSearchIndexHelperEnabled(), "Atlas Search Index tests are disabled"); } private static boolean hasAtlasSearchIndexHelperEnabled() { @@ -84,7 +91,29 @@ private static boolean hasAtlasSearchIndexHelperEnabled() { @BeforeEach public void setUp() { - client = createMongoClient(getMongoClientSettings()); + MongoClientSettings mongoClientSettings = getMongoClientSettingsBuilder() + .writeConcern(WriteConcern.MAJORITY) + .readConcern(ReadConcern.MAJORITY) + .addCommandListener(new CommandListener() { + @Override + public void commandStarted(final CommandStartedEvent event) { + /* This test case examines scenarios where the write or read concern is not forwarded to the server + for any Atlas Index Search commands. If a write or read concern is included in the command, + the server will return an error. */ + if (isSearchIndexCommand(event)) { + BsonDocument command = event.getCommand(); + assertFalse(command.containsKey("writeConcern")); + assertFalse(command.containsKey("readConcern")); + } + } + + private boolean isSearchIndexCommand(final CommandStartedEvent event) { + return event.getCommand().toJson().contains("SearchIndex"); + } + }) + .build(); + + client = createMongoClient(mongoClientSettings); db = client.getDatabase("test"); String collectionName = UUID.randomUUID().toString(); From f7715c1c80ac32f133695208081fbe7ea9ff79a2 Mon Sep 17 00:00:00 2001 From: "slav.babanin" Date: Tue, 7 Nov 2023 15:57:53 -0800 Subject: [PATCH 07/47] Version: bump 4.11.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 95431773403..fb551529ff6 100644 --- a/build.gradle +++ b/build.gradle @@ -74,7 +74,7 @@ configure(coreProjects) { apply plugin: 'idea' group = 'org.mongodb' - version = '4.11.1-SNAPSHOT' + version = '4.11.1' repositories { mavenLocal() From 22af63e853d7b38523b30c8fdfa1498a2a2db683 Mon Sep 17 00:00:00 2001 From: "slav.babanin" Date: Tue, 7 Nov 2023 15:58:06 -0800 Subject: [PATCH 08/47] Version: bump 4.11.2-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index fb551529ff6..e53021499a1 100644 --- a/build.gradle +++ b/build.gradle @@ -74,7 +74,7 @@ configure(coreProjects) { apply plugin: 'idea' group = 'org.mongodb' - version = '4.11.1' + version = '4.11.2-SNAPSHOT' repositories { mavenLocal() From b155d88c8dd89f453b45af87d46c6a528dd724ca Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Wed, 6 Dec 2023 10:51:57 -0500 Subject: [PATCH 09/47] Install legacy shell JAVA-4791 --- .evergreen/.evg.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.evergreen/.evg.yml b/.evergreen/.evg.yml index bab2690ff82..4aa9ec762e9 100644 --- a/.evergreen/.evg.yml +++ b/.evergreen/.evg.yml @@ -148,7 +148,9 @@ functions: params: script: | ${PREPARE_SHELL} - REQUIRE_API_VERSION=${REQUIRE_API_VERSION} LOAD_BALANCER=${LOAD_BALANCER} MONGODB_VERSION=${VERSION} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} SKIP_LEGACY_SHELL=${SKIP_LEGACY_SHELL} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh + REQUIRE_API_VERSION=${REQUIRE_API_VERSION} LOAD_BALANCER=${LOAD_BALANCER} MONGODB_VERSION=${VERSION} TOPOLOGY=${TOPOLOGY} \ + AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} \ + INSTALL_LEGACY_SHELL=${INSTALL_LEGACY_SHELL} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh # run-orchestration generates expansion file with the MONGODB_URI for the cluster - command: expansions.update params: @@ -950,6 +952,7 @@ tasks: AUTH: "auth" ORCHESTRATION_FILE: "auth-aws.json" TOPOLOGY: "server" + INSTALL_LEGACY_SHELL: "true" - func: "add aws auth variables to file" - func: "run aws auth test with regular aws credentials" @@ -960,6 +963,7 @@ tasks: AUTH: "auth" ORCHESTRATION_FILE: "auth-aws.json" TOPOLOGY: "server" + INSTALL_LEGACY_SHELL: "true" - func: "add aws auth variables to file" - func: "run aws auth test with assume role credentials" @@ -970,6 +974,7 @@ tasks: AUTH: "auth" ORCHESTRATION_FILE: "auth-aws.json" TOPOLOGY: "server" + INSTALL_LEGACY_SHELL: "true" - func: "add aws auth variables to file" - func: "run aws auth test with aws credentials as environment variables" @@ -980,6 +985,7 @@ tasks: AUTH: "auth" ORCHESTRATION_FILE: "auth-aws.json" TOPOLOGY: "server" + INSTALL_LEGACY_SHELL: "true" - func: "add aws auth variables to file" - func: "run aws auth test with aws credentials and session token as environment variables" @@ -990,6 +996,7 @@ tasks: AUTH: "auth" ORCHESTRATION_FILE: "auth-aws.json" TOPOLOGY: "server" + INSTALL_LEGACY_SHELL: "true" - func: "add aws auth variables to file" - func: "run aws auth test with aws EC2 credentials" @@ -1000,6 +1007,7 @@ tasks: AUTH: "auth" ORCHESTRATION_FILE: "auth-aws.json" TOPOLOGY: "server" + INSTALL_LEGACY_SHELL: "true" - func: "add aws auth variables to file" - func: "run aws auth test with web identity credentials" @@ -1010,6 +1018,7 @@ tasks: AUTH: "auth" ORCHESTRATION_FILE: "auth-aws.json" TOPOLOGY: "server" + INSTALL_LEGACY_SHELL: "true" - func: "add aws auth variables to file" - func: "run aws ECS auth test" @@ -1473,7 +1482,6 @@ tasks: TOPOLOGY: "server" SSL: "nossl" AUTH: "noauth" - SKIP_LEGACY_SHELL: "true" - func: "run perf tests" - func: "send dashboard data" From 9a3c9ddc3b56eb80cb4e0ed9f3617c7c31fdb8d3 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Fri, 5 Jan 2024 10:28:57 -0500 Subject: [PATCH 10/47] Don't gossip cluster time from monitoring connections (#1276) JAVA-5256 --- .../internal/connection/CommandHelper.java | 18 ++++---------- .../DefaultClusterableServerFactory.java | 2 +- .../connection/DefaultServerMonitor.java | 9 +++---- .../CommandHelperSpecification.groovy | 24 ------------------- .../ServerMonitorSpecification.groovy | 1 - .../DefaultServerMonitorSpecification.groovy | 6 ++--- 6 files changed, 11 insertions(+), 49 deletions(-) diff --git a/driver-core/src/main/com/mongodb/internal/connection/CommandHelper.java b/driver-core/src/main/com/mongodb/internal/connection/CommandHelper.java index 075aa19d190..ccf80716a23 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/CommandHelper.java +++ b/driver-core/src/main/com/mongodb/internal/connection/CommandHelper.java @@ -22,7 +22,6 @@ import com.mongodb.connection.ClusterConnectionMode; import com.mongodb.internal.IgnorableRequestContext; import com.mongodb.internal.async.SingleResultCallback; -import com.mongodb.internal.session.SessionContext; import com.mongodb.internal.validator.NoOpFieldNameValidator; import com.mongodb.lang.Nullable; import org.bson.BsonDocument; @@ -46,20 +45,14 @@ public final class CommandHelper { static BsonDocument executeCommand(final String database, final BsonDocument command, final ClusterConnectionMode clusterConnectionMode, @Nullable final ServerApi serverApi, final InternalConnection internalConnection) { - return sendAndReceive(database, command, null, clusterConnectionMode, serverApi, internalConnection); - } - - public static BsonDocument executeCommand(final String database, final BsonDocument command, final ClusterClock clusterClock, - final ClusterConnectionMode clusterConnectionMode, @Nullable final ServerApi serverApi, - final InternalConnection internalConnection) { - return sendAndReceive(database, command, clusterClock, clusterConnectionMode, serverApi, internalConnection); + return sendAndReceive(database, command, clusterConnectionMode, serverApi, internalConnection); } static BsonDocument executeCommandWithoutCheckingForFailure(final String database, final BsonDocument command, final ClusterConnectionMode clusterConnectionMode, @Nullable final ServerApi serverApi, final InternalConnection internalConnection) { try { - return sendAndReceive(database, command, null, clusterConnectionMode, serverApi, internalConnection); + return sendAndReceive(database, command, clusterConnectionMode, serverApi, internalConnection); } catch (MongoServerException e) { return new BsonDocument(); } @@ -94,14 +87,11 @@ static boolean isCommandOk(final BsonDocument response) { } private static BsonDocument sendAndReceive(final String database, final BsonDocument command, - @Nullable final ClusterClock clusterClock, final ClusterConnectionMode clusterConnectionMode, @Nullable final ServerApi serverApi, final InternalConnection internalConnection) { - SessionContext sessionContext = clusterClock == null ? NoOpSessionContext.INSTANCE - : new ClusterClockAdvancingSessionContext(NoOpSessionContext.INSTANCE, clusterClock); return assertNotNull(internalConnection.sendAndReceive(getCommandMessage(database, command, internalConnection, - clusterConnectionMode, serverApi), new BsonDocumentCodec(), sessionContext, IgnorableRequestContext.INSTANCE, - new OperationContext())); + clusterConnectionMode, serverApi), new BsonDocumentCodec(), NoOpSessionContext.INSTANCE, + IgnorableRequestContext.INSTANCE, new OperationContext())); } private static CommandMessage getCommandMessage(final String database, final BsonDocument command, diff --git a/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterableServerFactory.java b/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterableServerFactory.java index 9b8ac1399b3..a82ed994216 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterableServerFactory.java +++ b/driver-core/src/main/com/mongodb/internal/connection/DefaultClusterableServerFactory.java @@ -89,7 +89,7 @@ public ClusterableServer create(final Cluster cluster, final ServerAddress serve ServerId serverId = new ServerId(cluster.getClusterId(), serverAddress); ClusterConnectionMode clusterMode = cluster.getSettings().getMode(); SameObjectProvider sdamProvider = SameObjectProvider.uninitialized(); - ServerMonitor serverMonitor = new DefaultServerMonitor(serverId, serverSettings, cluster.getClock(), + ServerMonitor serverMonitor = new DefaultServerMonitor(serverId, serverSettings, // no credentials, compressor list, or command listener for the server monitor factory new InternalStreamConnectionFactory(clusterMode, true, heartbeatStreamFactory, null, applicationName, mongoDriverInformation, emptyList(), loggerSettings, null, serverApi, inetAddressResolver), diff --git a/driver-core/src/main/com/mongodb/internal/connection/DefaultServerMonitor.java b/driver-core/src/main/com/mongodb/internal/connection/DefaultServerMonitor.java index 9ad1f49e613..02dc1966b79 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/DefaultServerMonitor.java +++ b/driver-core/src/main/com/mongodb/internal/connection/DefaultServerMonitor.java @@ -71,7 +71,6 @@ class DefaultServerMonitor implements ServerMonitor { private final ServerId serverId; private final ServerMonitorListener serverMonitorListener; - private final ClusterClock clusterClock; private final Provider sdamProvider; private final InternalConnectionFactory internalConnectionFactory; private final ClusterConnectionMode clusterConnectionMode; @@ -88,15 +87,13 @@ class DefaultServerMonitor implements ServerMonitor { private volatile boolean isClosed; DefaultServerMonitor(final ServerId serverId, final ServerSettings serverSettings, - final ClusterClock clusterClock, - final InternalConnectionFactory internalConnectionFactory, + final InternalConnectionFactory internalConnectionFactory, final ClusterConnectionMode clusterConnectionMode, @Nullable final ServerApi serverApi, final Provider sdamProvider) { this.serverSettings = notNull("serverSettings", serverSettings); this.serverId = notNull("serverId", serverId); this.serverMonitorListener = singleServerMonitorListener(serverSettings); - this.clusterClock = notNull("clusterClock", clusterClock); this.internalConnectionFactory = notNull("internalConnectionFactory", internalConnectionFactory); this.clusterConnectionMode = notNull("clusterConnectionMode", clusterConnectionMode); this.serverApi = serverApi; @@ -206,7 +203,7 @@ private ServerDescription lookupServerDescription(final ServerDescription curren long start = System.nanoTime(); try { - SessionContext sessionContext = new ClusterClockAdvancingSessionContext(NoOpSessionContext.INSTANCE, clusterClock); + SessionContext sessionContext = NoOpSessionContext.INSTANCE; if (!connection.hasMoreToCome()) { BsonDocument helloDocument = new BsonDocument(getHandshakeCommandName(currentServerDescription), new BsonInt32(1)) .append("helloOk", BsonBoolean.TRUE); @@ -432,7 +429,7 @@ private void pingServer(final InternalConnection connection) { long start = System.nanoTime(); executeCommand("admin", new BsonDocument(getHandshakeCommandName(connection.getInitialServerDescription()), new BsonInt32(1)), - clusterClock, clusterConnectionMode, serverApi, connection); + clusterConnectionMode, serverApi, connection); long elapsedTimeNanos = System.nanoTime() - start; averageRoundTripTime.addSample(elapsedTimeNanos); } diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/CommandHelperSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/CommandHelperSpecification.groovy index 4f6f360d857..a1fea1e7515 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/CommandHelperSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/CommandHelperSpecification.groovy @@ -18,18 +18,13 @@ package com.mongodb.internal.connection import com.mongodb.LoggerSettings import com.mongodb.MongoCommandException -import com.mongodb.ServerAddress import com.mongodb.connection.ClusterConnectionMode import com.mongodb.connection.ClusterId -import com.mongodb.connection.ConnectionDescription -import com.mongodb.connection.ConnectionId import com.mongodb.connection.ServerId -import com.mongodb.connection.ServerType import com.mongodb.connection.SocketSettings import com.mongodb.connection.netty.NettyStreamFactory import org.bson.BsonDocument import org.bson.BsonInt32 -import org.bson.BsonTimestamp import spock.lang.Specification import java.util.concurrent.CountDownLatch @@ -40,7 +35,6 @@ import static com.mongodb.ClusterFixture.getCredentialWithCache import static com.mongodb.ClusterFixture.getPrimary import static com.mongodb.ClusterFixture.getServerApi import static com.mongodb.ClusterFixture.getSslSettings -import static com.mongodb.internal.connection.CommandHelper.executeCommand import static com.mongodb.internal.connection.CommandHelper.executeCommandAsync class CommandHelperSpecification extends Specification { @@ -58,24 +52,6 @@ class CommandHelperSpecification extends Specification { connection?.close() } - def 'should gossip cluster time'() { - given: - def connection = Mock(InternalStreamConnection) { - getDescription() >> new ConnectionDescription(new ConnectionId(new ServerId(new ClusterId(), new ServerAddress())), - 6, ServerType.REPLICA_SET_PRIMARY, 1000, 1000, 1000, []) - } - def clusterClock = new ClusterClock() - clusterClock.advance(new BsonDocument('clusterTime', new BsonTimestamp(42L))) - - when: - executeCommand('admin', new BsonDocument(LEGACY_HELLO, new BsonInt32(1)), clusterClock, getClusterConnectionMode(), - getServerApi(), connection) - - then: - 1 * connection.sendAndReceive(_, _, _ as ClusterClockAdvancingSessionContext, _, _) >> new BsonDocument() - } - - def 'should execute command asynchronously'() { when: BsonDocument receivedDocument = null diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/ServerMonitorSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/connection/ServerMonitorSpecification.groovy index 6d1cb0133db..68b2e61464e 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/ServerMonitorSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/ServerMonitorSpecification.groovy @@ -221,7 +221,6 @@ class ServerMonitorSpecification extends OperationFunctionalSpecification { } } serverMonitor = new DefaultServerMonitor(new ServerId(new ClusterId(), address), ServerSettings.builder().build(), - new ClusterClock(), new InternalStreamConnectionFactory(SINGLE, new SocketStreamFactory(SocketSettings.builder() .connectTimeout(500, TimeUnit.MILLISECONDS) .build(), diff --git a/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerMonitorSpecification.groovy b/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerMonitorSpecification.groovy index d1790a8acb7..beaa9f75c0e 100644 --- a/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerMonitorSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/internal/connection/DefaultServerMonitorSpecification.groovy @@ -84,7 +84,7 @@ class DefaultServerMonitorSpecification extends Specification { } } monitor = new DefaultServerMonitor(new ServerId(new ClusterId(), new ServerAddress()), ServerSettings.builder().build(), - new ClusterClock(), internalConnectionFactory, ClusterConnectionMode.SINGLE, null, SameObjectProvider.initialized(sdam)) + internalConnectionFactory, ClusterConnectionMode.SINGLE, null, SameObjectProvider.initialized(sdam)) monitor.start() when: @@ -169,7 +169,7 @@ class DefaultServerMonitorSpecification extends Specification { } monitor = new DefaultServerMonitor(new ServerId(new ClusterId(), new ServerAddress()), ServerSettings.builder().heartbeatFrequency(1, TimeUnit.SECONDS).addServerMonitorListener(serverMonitorListener).build(), - new ClusterClock(), internalConnectionFactory, ClusterConnectionMode.SINGLE, null, mockSdamProvider()) + internalConnectionFactory, ClusterConnectionMode.SINGLE, null, mockSdamProvider()) when: monitor.start() @@ -250,7 +250,7 @@ class DefaultServerMonitorSpecification extends Specification { } monitor = new DefaultServerMonitor(new ServerId(new ClusterId(), new ServerAddress()), ServerSettings.builder().heartbeatFrequency(1, TimeUnit.SECONDS).addServerMonitorListener(serverMonitorListener).build(), - new ClusterClock(), internalConnectionFactory, ClusterConnectionMode.SINGLE, null, mockSdamProvider()) + internalConnectionFactory, ClusterConnectionMode.SINGLE, null, mockSdamProvider()) when: monitor.start() From aa5f77b0b7055b38a8734bf4478c8e2297a6894d Mon Sep 17 00:00:00 2001 From: raelg <344980+raelg@users.noreply.github.com> Date: Wed, 10 Jan 2024 19:50:10 +0000 Subject: [PATCH 11/47] Reclaim native memory quicker when using ZlibCompressor (#1285) Reclaim native memory quicker by overriding close() on DeflaterOutputStream to invoke end() on the Deflater, since by supplying a deflater to the constructor of DeflaterOutputStream usesDefaultDeflater is set to false and therefore end() is not invoked in DeflaterOutputStream#close. JAVA-5280 --- .../mongodb/internal/connection/ZlibCompressor.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/driver-core/src/main/com/mongodb/internal/connection/ZlibCompressor.java b/driver-core/src/main/com/mongodb/internal/connection/ZlibCompressor.java index b2f4768b541..e826b626a79 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/ZlibCompressor.java +++ b/driver-core/src/main/com/mongodb/internal/connection/ZlibCompressor.java @@ -18,6 +18,7 @@ import com.mongodb.MongoCompressor; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.Deflater; @@ -48,6 +49,15 @@ InputStream getInputStream(final InputStream source) { @Override OutputStream getOutputStream(final OutputStream source) { - return new DeflaterOutputStream(source, new Deflater(level)); + return new DeflaterOutputStream(source, new Deflater(level)) { + @Override + public void close() throws IOException { + try { + super.close(); + } finally { + def.end(); + } + } + }; } } From 2ef2bf92051caffd0b892aeea63c9c32f3d69bf8 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Tue, 12 Mar 2024 16:43:50 -0400 Subject: [PATCH 12/47] Convert Bson to BsonDocument for hint (#1335) Unlike every other instance of Bson in the CRUD API, the hint option for write operations was not converted to a BsonDocument prior to passing it down to the operation layer. This is a problem because the operation layer doesn't have a CodecRegistry available, and so can not properly due the conversion. In this commit, all hint options are converted to BsonDocument in the same place as all the other Bson options, where a CodecRegistry is available to properly do the conversion. JAVA-5357 --- .../mongodb/internal/bulk/DeleteRequest.java | 7 +++---- .../mongodb/internal/bulk/UpdateRequest.java | 7 +++---- .../internal/connection/SplittablePayload.java | 6 +++--- .../operation/BaseFindAndModifyOperation.java | 9 ++++----- .../operation/FindAndDeleteOperation.java | 3 +-- .../operation/FindAndReplaceOperation.java | 3 +-- .../operation/FindAndUpdateOperation.java | 3 +-- .../mongodb/internal/operation/Operations.java | 18 +++++++++--------- 8 files changed, 25 insertions(+), 31 deletions(-) diff --git a/driver-core/src/main/com/mongodb/internal/bulk/DeleteRequest.java b/driver-core/src/main/com/mongodb/internal/bulk/DeleteRequest.java index 587b24293f1..bcbf43142c1 100644 --- a/driver-core/src/main/com/mongodb/internal/bulk/DeleteRequest.java +++ b/driver-core/src/main/com/mongodb/internal/bulk/DeleteRequest.java @@ -19,7 +19,6 @@ import com.mongodb.client.model.Collation; import com.mongodb.lang.Nullable; import org.bson.BsonDocument; -import org.bson.conversions.Bson; import static com.mongodb.assertions.Assertions.notNull; @@ -32,7 +31,7 @@ public final class DeleteRequest extends WriteRequest { private final BsonDocument filter; private boolean isMulti = true; private Collation collation; - private Bson hint; + private BsonDocument hint; private String hintString; public DeleteRequest(final BsonDocument filter) { @@ -63,11 +62,11 @@ public DeleteRequest collation(@Nullable final Collation collation) { } @Nullable - public Bson getHint() { + public BsonDocument getHint() { return hint; } - public DeleteRequest hint(@Nullable final Bson hint) { + public DeleteRequest hint(@Nullable final BsonDocument hint) { this.hint = hint; return this; } diff --git a/driver-core/src/main/com/mongodb/internal/bulk/UpdateRequest.java b/driver-core/src/main/com/mongodb/internal/bulk/UpdateRequest.java index 454d0b3ba0d..5a7df089641 100644 --- a/driver-core/src/main/com/mongodb/internal/bulk/UpdateRequest.java +++ b/driver-core/src/main/com/mongodb/internal/bulk/UpdateRequest.java @@ -20,7 +20,6 @@ import com.mongodb.lang.Nullable; import org.bson.BsonDocument; import org.bson.BsonValue; -import org.bson.conversions.Bson; import java.util.List; @@ -39,7 +38,7 @@ public final class UpdateRequest extends WriteRequest { private boolean isUpsert = false; private Collation collation; private List arrayFilters; - @Nullable private Bson hint; + @Nullable private BsonDocument hint; @Nullable private String hintString; public UpdateRequest(final BsonDocument filter, @Nullable final BsonValue update, final Type updateType) { @@ -111,11 +110,11 @@ public List getArrayFilters() { } @Nullable - public Bson getHint() { + public BsonDocument getHint() { return hint; } - public UpdateRequest hint(@Nullable final Bson hint) { + public UpdateRequest hint(@Nullable final BsonDocument hint) { this.hint = hint; return this; } diff --git a/driver-core/src/main/com/mongodb/internal/connection/SplittablePayload.java b/driver-core/src/main/com/mongodb/internal/connection/SplittablePayload.java index 50300ceeac0..a71f7a940f0 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/SplittablePayload.java +++ b/driver-core/src/main/com/mongodb/internal/connection/SplittablePayload.java @@ -246,8 +246,8 @@ public void encode(final BsonWriter writer, final WriteRequestWithIndex writeReq } if (update.getHint() != null) { writer.writeName("hint"); - BsonDocument hint = assertNotNull(update.getHint()).toBsonDocument(BsonDocument.class, null); - getCodec(hint).encode(writer, hint, EncoderContext.builder().build()); + getCodec(assertNotNull(update.getHint())).encode(writer, assertNotNull(update.getHint()), + EncoderContext.builder().build()); } else if (update.getHintString() != null) { writer.writeString("hint", update.getHintString()); } @@ -265,7 +265,7 @@ public void encode(final BsonWriter writer, final WriteRequestWithIndex writeReq } if (deleteRequest.getHint() != null) { writer.writeName("hint"); - BsonDocument hint = assertNotNull(deleteRequest.getHint()).toBsonDocument(BsonDocument.class, null); + BsonDocument hint = assertNotNull(deleteRequest.getHint()); getCodec(hint).encode(writer, hint, EncoderContext.builder().build()); } else if (deleteRequest.getHintString() != null) { writer.writeString("hint", deleteRequest.getHintString()); diff --git a/driver-core/src/main/com/mongodb/internal/operation/BaseFindAndModifyOperation.java b/driver-core/src/main/com/mongodb/internal/operation/BaseFindAndModifyOperation.java index e3ae79fa589..5179d3096b3 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/BaseFindAndModifyOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/BaseFindAndModifyOperation.java @@ -31,7 +31,6 @@ import org.bson.BsonValue; import org.bson.FieldNameValidator; import org.bson.codecs.Decoder; -import org.bson.conversions.Bson; import java.util.concurrent.TimeUnit; @@ -62,7 +61,7 @@ public abstract class BaseFindAndModifyOperation implements AsyncWriteOperati private BsonDocument sort; private long maxTimeMS; private Collation collation; - private Bson hint; + private BsonDocument hint; private String hintString; private BsonValue comment; private BsonDocument variables; @@ -151,11 +150,11 @@ public Collation getCollation() { } @Nullable - public Bson getHint() { + public BsonDocument getHint() { return hint; } - public BaseFindAndModifyOperation hint(@Nullable final Bson hint) { + public BaseFindAndModifyOperation hint(@Nullable final BsonDocument hint) { this.hint = hint; return this; } @@ -216,7 +215,7 @@ private CommandCreator getCommandCreator(final SessionContext sessionContext) { if (getHint() != null || getHintString() != null) { validateHintForFindAndModify(connectionDescription, getWriteConcern()); if (getHint() != null) { - commandDocument.put("hint", getHint().toBsonDocument(BsonDocument.class, null)); + commandDocument.put("hint", getHint()); } else { commandDocument.put("hint", new BsonString(getHintString())); } diff --git a/driver-core/src/main/com/mongodb/internal/operation/FindAndDeleteOperation.java b/driver-core/src/main/com/mongodb/internal/operation/FindAndDeleteOperation.java index ede7ee51628..928173ba2fb 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/FindAndDeleteOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/FindAndDeleteOperation.java @@ -27,7 +27,6 @@ import org.bson.BsonValue; import org.bson.FieldNameValidator; import org.bson.codecs.Decoder; -import org.bson.conversions.Bson; import java.util.concurrent.TimeUnit; @@ -68,7 +67,7 @@ public FindAndDeleteOperation sort(@Nullable final BsonDocument sort) { } @Override - public FindAndDeleteOperation hint(@Nullable final Bson hint) { + public FindAndDeleteOperation hint(@Nullable final BsonDocument hint) { super.hint(hint); return this; } diff --git a/driver-core/src/main/com/mongodb/internal/operation/FindAndReplaceOperation.java b/driver-core/src/main/com/mongodb/internal/operation/FindAndReplaceOperation.java index de988c963a4..303d9c0e208 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/FindAndReplaceOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/FindAndReplaceOperation.java @@ -29,7 +29,6 @@ import org.bson.BsonValue; import org.bson.FieldNameValidator; import org.bson.codecs.Decoder; -import org.bson.conversions.Bson; import java.util.HashMap; import java.util.Map; @@ -111,7 +110,7 @@ public FindAndReplaceOperation sort(@Nullable final BsonDocument sort) { } @Override - public FindAndReplaceOperation hint(@Nullable final Bson hint) { + public FindAndReplaceOperation hint(@Nullable final BsonDocument hint) { super.hint(hint); return this; } diff --git a/driver-core/src/main/com/mongodb/internal/operation/FindAndUpdateOperation.java b/driver-core/src/main/com/mongodb/internal/operation/FindAndUpdateOperation.java index 17ce879102d..2c2a00ff437 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/FindAndUpdateOperation.java +++ b/driver-core/src/main/com/mongodb/internal/operation/FindAndUpdateOperation.java @@ -30,7 +30,6 @@ import org.bson.BsonValue; import org.bson.FieldNameValidator; import org.bson.codecs.Decoder; -import org.bson.conversions.Bson; import java.util.HashMap; import java.util.List; @@ -139,7 +138,7 @@ public FindAndUpdateOperation sort(@Nullable final BsonDocument sort) { } @Override - public FindAndUpdateOperation hint(@Nullable final Bson hint) { + public FindAndUpdateOperation hint(@Nullable final BsonDocument hint) { super.hint(hint); return this; } diff --git a/driver-core/src/main/com/mongodb/internal/operation/Operations.java b/driver-core/src/main/com/mongodb/internal/operation/Operations.java index ed84e9b2e72..1a58f1ad9a1 100644 --- a/driver-core/src/main/com/mongodb/internal/operation/Operations.java +++ b/driver-core/src/main/com/mongodb/internal/operation/Operations.java @@ -326,7 +326,7 @@ FindAndDeleteOperation findOneAndDelete(final Bson filter, final Find .sort(toBsonDocument(options.getSort())) .maxTime(options.getMaxTime(MILLISECONDS), MILLISECONDS) .collation(options.getCollation()) - .hint(options.getHint()) + .hint(toBsonDocument(options.getHint())) .hintString(options.getHintString()) .comment(options.getComment()) .let(toBsonDocument(options.getLet())); @@ -344,7 +344,7 @@ FindAndReplaceOperation findOneAndReplace(final Bson filter, final TD .maxTime(options.getMaxTime(MILLISECONDS), MILLISECONDS) .bypassDocumentValidation(options.getBypassDocumentValidation()) .collation(options.getCollation()) - .hint(options.getHint()) + .hint(toBsonDocument(options.getHint())) .hintString(options.getHintString()) .comment(options.getComment()) .let(toBsonDocument(options.getLet())); @@ -362,7 +362,7 @@ FindAndUpdateOperation findOneAndUpdate(final Bson filter, final Bson .bypassDocumentValidation(options.getBypassDocumentValidation()) .collation(options.getCollation()) .arrayFilters(toBsonDocumentList(options.getArrayFilters())) - .hint(options.getHint()) + .hint(toBsonDocument(options.getHint())) .hintString(options.getHintString()) .comment(options.getComment()) .let(toBsonDocument(options.getLet())); @@ -381,7 +381,7 @@ FindAndUpdateOperation findOneAndUpdate(final Bson filter, final List .bypassDocumentValidation(options.getBypassDocumentValidation()) .collation(options.getCollation()) .arrayFilters(toBsonDocumentList(options.getArrayFilters())) - .hint(options.getHint()) + .hint(toBsonDocument(options.getHint())) .hintString(options.getHintString()) .comment(options.getComment()) .let(toBsonDocument(options.getLet())); @@ -474,7 +474,7 @@ MixedBulkWriteOperation bulkWrite(final List updateOneModel = (UpdateOneModel) writeModel; @@ -485,7 +485,7 @@ MixedBulkWriteOperation bulkWrite(final List updateManyModel = (UpdateManyModel) writeModel; @@ -496,19 +496,19 @@ MixedBulkWriteOperation bulkWrite(final List deleteOneModel = (DeleteOneModel) writeModel; writeRequest = new DeleteRequest(assertNotNull(toBsonDocument(deleteOneModel.getFilter()))).multi(false) .collation(deleteOneModel.getOptions().getCollation()) - .hint(deleteOneModel.getOptions().getHint()) + .hint(toBsonDocument(deleteOneModel.getOptions().getHint())) .hintString(deleteOneModel.getOptions().getHintString()); } else if (writeModel instanceof DeleteManyModel) { DeleteManyModel deleteManyModel = (DeleteManyModel) writeModel; writeRequest = new DeleteRequest(assertNotNull(toBsonDocument(deleteManyModel.getFilter()))).multi(true) .collation(deleteManyModel.getOptions().getCollation()) - .hint(deleteManyModel.getOptions().getHint()) + .hint(toBsonDocument(deleteManyModel.getOptions().getHint())) .hintString(deleteManyModel.getOptions().getHintString()); } else { throw new UnsupportedOperationException(format("WriteModel of type %s is not supported", writeModel.getClass())); From 375bbd68e1da7b17d539a111278e8f21e2f1c4f8 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Tue, 27 Feb 2024 19:04:06 -0500 Subject: [PATCH 13/47] Fix test failures on 8.0 sharded clusters (#1319) Advance cluster time on all session entities in unified tests to one after the initial data is created JAVA-5334 --- .../com/mongodb/client/test/CollectionHelper.java | 5 +++++ .../com/mongodb/client/unified/Entities.java | 8 +++++--- .../com/mongodb/client/unified/UnifiedTest.java | 10 +++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java b/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java index e2216629a7a..bdcf8ef9305 100644 --- a/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java +++ b/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java @@ -109,6 +109,11 @@ public static void dropDatabase(final String name, final WriteConcern writeConce } } + public static BsonDocument getCurrentClusterTime() { + return new CommandReadOperation("admin", new BsonDocument("ping", new BsonInt32(1)), new BsonDocumentCodec()) + .execute(getBinding()).getDocument("$clusterTime", null); + } + public MongoNamespace getNamespace() { return namespace; } diff --git a/driver-sync/src/test/functional/com/mongodb/client/unified/Entities.java b/driver-sync/src/test/functional/com/mongodb/client/unified/Entities.java index 3bc32e26c26..e909388759c 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/unified/Entities.java +++ b/driver-sync/src/test/functional/com/mongodb/client/unified/Entities.java @@ -23,7 +23,6 @@ import com.mongodb.ReadConcernLevel; import com.mongodb.ServerApi; import com.mongodb.ServerApiVersion; -import com.mongodb.logging.TestLoggingInterceptor; import com.mongodb.TransactionOptions; import com.mongodb.WriteConcern; import com.mongodb.assertions.Assertions; @@ -60,6 +59,7 @@ import com.mongodb.internal.connection.TestServerListener; import com.mongodb.internal.logging.LogMessage; import com.mongodb.lang.NonNull; +import com.mongodb.logging.TestLoggingInterceptor; import org.bson.BsonArray; import org.bson.BsonBoolean; import org.bson.BsonDocument; @@ -294,6 +294,7 @@ private void putEntity(final String id, final T entity, final Map } public void init(final BsonArray entitiesArray, + final BsonDocument startingClusterTime, final boolean waitForPoolAsyncWorkManagerStart, final Function mongoClientSupplier, final Function gridFSBucketSupplier, @@ -318,7 +319,7 @@ public void init(final BsonArray entitiesArray, break; } case "session": { - initSession(entity, id); + initSession(entity, id, startingClusterTime); break; } case "bucket": { @@ -586,7 +587,7 @@ private void initCollection(final BsonDocument entity, final String id) { putEntity(id, collection, collections); } - private void initSession(final BsonDocument entity, final String id) { + private void initSession(final BsonDocument entity, final String id, final BsonDocument startingClusterTime) { MongoClient client = clients.get(entity.getString("client").getValue()); ClientSessionOptions.Builder optionsBuilder = ClientSessionOptions.builder(); if (entity.containsKey("sessionOptions")) { @@ -604,6 +605,7 @@ private void initSession(final BsonDocument entity, final String id) { } } ClientSession session = client.startSession(optionsBuilder.build()); + session.advanceClusterTime(startingClusterTime); putEntity(id, session, sessions); putEntity(id + "-identifier", session.getServerSession().getIdentifier(), sessionIdentifiers); } 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 0ae4b644975..a9d25b0735d 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 @@ -71,6 +71,7 @@ import static com.mongodb.ClusterFixture.getServerVersion; import static com.mongodb.client.Fixture.getMongoClient; import static com.mongodb.client.Fixture.getMongoClientSettings; +import static com.mongodb.client.test.CollectionHelper.getCurrentClusterTime; import static com.mongodb.client.unified.RunOnRequirementsMatcher.runOnRequirementsMet; import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; @@ -102,6 +103,7 @@ public abstract class UnifiedTest { private final UnifiedClientEncryptionHelper clientEncryptionHelper = new UnifiedClientEncryptionHelper(entities); private final List failPoints = new ArrayList<>(); private final UnifiedTestContext rootContext = new UnifiedTestContext(); + private BsonDocument startingClusterTime; private class UnifiedTestContext { private final AssertionContext context = new AssertionContext(); @@ -209,12 +211,12 @@ public void setUp() { if (definition.containsKey("skipReason")) { throw new AssumptionViolatedException(definition.getString("skipReason").getValue()); } - entities.init(entitiesArray, + startingClusterTime = addInitialDataAndGetClusterTime(); + entities.init(entitiesArray, startingClusterTime, fileDescription != null && PRESTART_POOL_ASYNC_WORK_MANAGER_FILE_DESCRIPTIONS.contains(fileDescription), this::createMongoClient, this::createGridFSBucket, this::createClientEncryption); - addInitialData(); } @After @@ -550,6 +552,7 @@ protected boolean terminateLoop() { private OperationResult executeCreateEntities(final BsonDocument operation) { entities.init(operation.getDocument("arguments").getArray("entities"), + startingClusterTime, false, this::createMongoClient, this::createGridFSBucket, @@ -871,7 +874,7 @@ private List lastTwoCommandEvents(final TestCommandListener listen return events.subList(events.size() - 2, events.size()); } - private void addInitialData() { + private BsonDocument addInitialDataAndGetClusterTime() { for (BsonValue cur : initialData.getValues()) { BsonDocument curDataSet = cur.asDocument(); CollectionHelper helper = new CollectionHelper<>(new BsonDocumentCodec(), @@ -886,5 +889,6 @@ private void addInitialData() { WriteConcern.MAJORITY); } } + return getCurrentClusterTime(); } } From d9bedd49ab2ece07d08799ea2e69b9b8c6225bb9 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Fri, 15 Mar 2024 14:36:03 +0000 Subject: [PATCH 14/47] Support discriminators not being the first field when decoding (#1324) JAVA-5304 --- .../org/bson/codecs/kotlinx/BsonDecoder.kt | 100 ++++++++++++++---- .../KotlinSerializerCodecProviderTest.kt | 48 ++++++++- .../kotlinx/KotlinSerializerCodecTest.kt | 49 +++++++-- .../codecs/kotlinx/samples/DataClasses.kt | 9 ++ 4 files changed, 172 insertions(+), 34 deletions(-) diff --git a/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonDecoder.kt b/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonDecoder.kt index b4cbad3b9dd..435964d4ac0 100644 --- a/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonDecoder.kt +++ b/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonDecoder.kt @@ -31,6 +31,7 @@ import kotlinx.serialization.modules.SerializersModule import org.bson.AbstractBsonReader import org.bson.BsonInvalidOperationException import org.bson.BsonReader +import org.bson.BsonReaderMark import org.bson.BsonType import org.bson.BsonValue import org.bson.codecs.BsonValueCodec @@ -68,6 +69,20 @@ internal open class DefaultBsonDecoder( val validKeyKinds = setOf(PrimitiveKind.STRING, PrimitiveKind.CHAR, SerialKind.ENUM) val bsonValueCodec = BsonValueCodec() const val UNKNOWN_INDEX = -10 + fun validateCurrentBsonType( + reader: AbstractBsonReader, + expectedType: BsonType, + descriptor: SerialDescriptor, + actualType: (descriptor: SerialDescriptor) -> String = { it.kind.toString() } + ) { + reader.currentBsonType?.let { + if (it != expectedType) { + throw SerializationException( + "Invalid data for `${actualType(descriptor)}` expected a bson " + + "${expectedType.name.lowercase()} found: ${reader.currentBsonType}") + } + } + } } private fun initElementMetadata(descriptor: SerialDescriptor) { @@ -119,29 +134,14 @@ internal open class DefaultBsonDecoder( @Suppress("ReturnCount") override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder { - when (descriptor.kind) { - is StructureKind.LIST -> { - reader.readStartArray() - return BsonArrayDecoder(reader, serializersModule, configuration) - } - is PolymorphicKind -> { - reader.readStartDocument() - return PolymorphicDecoder(reader, serializersModule, configuration) - } + return when (descriptor.kind) { + is StructureKind.LIST -> BsonArrayDecoder(descriptor, reader, serializersModule, configuration) + is PolymorphicKind -> PolymorphicDecoder(descriptor, reader, serializersModule, configuration) is StructureKind.CLASS, - StructureKind.OBJECT -> { - val current = reader.currentBsonType - if (current == null || current == BsonType.DOCUMENT) { - reader.readStartDocument() - } - } - is StructureKind.MAP -> { - reader.readStartDocument() - return BsonDocumentDecoder(reader, serializersModule, configuration) - } + StructureKind.OBJECT -> BsonDocumentDecoder(descriptor, reader, serializersModule, configuration) + is StructureKind.MAP -> MapDecoder(descriptor, reader, serializersModule, configuration) else -> throw SerializationException("Primitives are not supported at top-level") } - return DefaultBsonDecoder(reader, serializersModule, configuration) } override fun endStructure(descriptor: SerialDescriptor) { @@ -194,10 +194,17 @@ internal open class DefaultBsonDecoder( @OptIn(ExperimentalSerializationApi::class) private class BsonArrayDecoder( + descriptor: SerialDescriptor, reader: AbstractBsonReader, serializersModule: SerializersModule, configuration: BsonConfiguration ) : DefaultBsonDecoder(reader, serializersModule, configuration) { + + init { + validateCurrentBsonType(reader, BsonType.ARRAY, descriptor) + reader.readStartArray() + } + private var index = 0 override fun decodeElementIndex(descriptor: SerialDescriptor): Int { val nextType = reader.readBsonType() @@ -208,18 +215,46 @@ private class BsonArrayDecoder( @OptIn(ExperimentalSerializationApi::class) private class PolymorphicDecoder( + descriptor: SerialDescriptor, reader: AbstractBsonReader, serializersModule: SerializersModule, configuration: BsonConfiguration ) : DefaultBsonDecoder(reader, serializersModule, configuration) { private var index = 0 + private var mark: BsonReaderMark? - override fun decodeSerializableValue(deserializer: DeserializationStrategy): T = - deserializer.deserialize(DefaultBsonDecoder(reader, serializersModule, configuration)) + init { + mark = reader.mark + validateCurrentBsonType(reader, BsonType.DOCUMENT, descriptor) { it.serialName } + reader.readStartDocument() + } + + override fun decodeSerializableValue(deserializer: DeserializationStrategy): T { + mark?.let { + it.reset() + mark = null + } + return deserializer.deserialize(DefaultBsonDecoder(reader, serializersModule, configuration)) + } override fun decodeElementIndex(descriptor: SerialDescriptor): Int { + var found = false return when (index) { - 0 -> index++ + 0 -> { + while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) { + if (reader.readName() == configuration.classDiscriminator) { + found = true + break + } + reader.skipValue() + } + if (!found) { + throw SerializationException( + "Missing required discriminator field `${configuration.classDiscriminator}` " + + "for polymorphic class: `${descriptor.serialName}`.") + } + index++ + } 1 -> index++ else -> DECODE_DONE } @@ -228,6 +263,20 @@ private class PolymorphicDecoder( @OptIn(ExperimentalSerializationApi::class) private class BsonDocumentDecoder( + descriptor: SerialDescriptor, + reader: AbstractBsonReader, + serializersModule: SerializersModule, + configuration: BsonConfiguration +) : DefaultBsonDecoder(reader, serializersModule, configuration) { + init { + validateCurrentBsonType(reader, BsonType.DOCUMENT, descriptor) { it.serialName } + reader.readStartDocument() + } +} + +@OptIn(ExperimentalSerializationApi::class) +private class MapDecoder( + descriptor: SerialDescriptor, reader: AbstractBsonReader, serializersModule: SerializersModule, configuration: BsonConfiguration @@ -236,6 +285,11 @@ private class BsonDocumentDecoder( private var index = 0 private var isKey = false + init { + validateCurrentBsonType(reader, BsonType.DOCUMENT, descriptor) + reader.readStartDocument() + } + override fun decodeString(): String { return if (isKey) { reader.readName() diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecProviderTest.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecProviderTest.kt index 0870e2033e9..e05fc8f34f1 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecProviderTest.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecProviderTest.kt @@ -16,14 +16,19 @@ package org.bson.codecs.kotlinx import com.mongodb.MongoClientSettings -import kotlin.test.assertEquals -import kotlin.test.assertNotNull -import kotlin.test.assertNull -import kotlin.test.assertTrue +import org.bson.codecs.DecoderContext import org.bson.codecs.kotlinx.samples.DataClassParameterized +import org.bson.codecs.kotlinx.samples.DataClassSealedInterface import org.bson.codecs.kotlinx.samples.DataClassWithSimpleValues +import org.bson.codecs.kotlinx.samples.SealedInterface import org.bson.conversions.Bson +import org.bson.json.JsonReader +import org.bson.types.ObjectId import org.junit.jupiter.api.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue class KotlinSerializerCodecProviderTest { @@ -60,4 +65,39 @@ class KotlinSerializerCodecProviderTest { assertTrue { codec is KotlinSerializerCodec } assertEquals(DataClassWithSimpleValues::class.java, codec.encoderClass) } + + @Test + fun testDataClassWithSimpleValuesFieldOrdering() { + val codec = MongoClientSettings.getDefaultCodecRegistry().get(DataClassWithSimpleValues::class.java) + val expected = DataClassWithSimpleValues('c', 0, 1, 22, 42L, 4.0f, 4.2, true, "String") + + val numberLong = "\$numberLong" + val actual = + codec.decode( + JsonReader( + """{"boolean": true, "byte": 0, "char": "c", "double": 4.2, "float": 4.0, "int": 22, + |"long": {"$numberLong": "42"}, "short": 1, "string": "String"}""" + .trimMargin()), + DecoderContext.builder().build()) + + assertEquals(expected, actual) + } + + @Test + fun testDataClassSealedFieldOrdering() { + val codec = MongoClientSettings.getDefaultCodecRegistry().get(SealedInterface::class.java) + + val objectId = ObjectId("111111111111111111111111") + val oid = "\$oid" + val expected = DataClassSealedInterface(objectId, "string") + val actual = + codec.decode( + JsonReader( + """{"name": "string", "_id": {$oid: "${objectId.toHexString()}"}, + |"_t": "org.bson.codecs.kotlinx.samples.DataClassSealedInterface"}""" + .trimMargin()), + DecoderContext.builder().build()) + + assertEquals(expected, actual) + } } diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt index 146e897c59b..14fcfa8a01c 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt @@ -84,20 +84,23 @@ import org.bson.codecs.kotlinx.samples.DataClassWithSequence import org.bson.codecs.kotlinx.samples.DataClassWithSimpleValues import org.bson.codecs.kotlinx.samples.DataClassWithTriple import org.bson.codecs.kotlinx.samples.Key +import org.bson.codecs.kotlinx.samples.SealedInterface import org.bson.codecs.kotlinx.samples.ValueClass import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows @OptIn(ExperimentalSerializationApi::class) +@Suppress("LargeClass") class KotlinSerializerCodecTest { private val numberLong = "\$numberLong" + private val oid = "\$oid" private val emptyDocument = "{}" private val altConfiguration = BsonConfiguration(encodeDefaults = false, classDiscriminator = "_t", explicitNulls = true) private val allBsonTypesJson = """{ - | "id": {"${'$'}oid": "111111111111111111111111"}, + | "id": {"$oid": "111111111111111111111111"}, | "arrayEmpty": [], | "arraySimple": [{"${'$'}numberInt": "1"}, {"${'$'}numberInt": "2"}, {"${'$'}numberInt": "3"}], | "arrayComplex": [{"a": {"${'$'}numberInt": "1"}}, {"a": {"${'$'}numberInt": "2"}}], @@ -668,17 +671,49 @@ class KotlinSerializerCodecTest { codec?.decode(BsonDocumentReader(data), DecoderContext.builder().build()) } - assertThrows("Invalid complex types") { - val data = BsonDocument.parse("""{"_id": "myId", "embedded": 123}""") - val codec = KotlinSerializerCodec.create() - codec?.decode(BsonDocumentReader(data), DecoderContext.builder().build()) - } - assertThrows("Failing init") { val data = BsonDocument.parse("""{"id": "myId"}""") val codec = KotlinSerializerCodec.create() codec?.decode(BsonDocumentReader(data), DecoderContext.builder().build()) } + + var exception = + assertThrows("Invalid complex types - document") { + val data = BsonDocument.parse("""{"_id": "myId", "embedded": 123}""") + val codec = KotlinSerializerCodec.create() + codec?.decode(BsonDocumentReader(data), DecoderContext.builder().build()) + } + assertEquals( + "Invalid data for `org.bson.codecs.kotlinx.samples.DataClassEmbedded` " + + "expected a bson document found: INT32", + exception.message) + + exception = + assertThrows("Invalid complex types - list") { + val data = BsonDocument.parse("""{"_id": "myId", "nested": 123}""") + val codec = KotlinSerializerCodec.create() + codec?.decode(BsonDocumentReader(data), DecoderContext.builder().build()) + } + assertEquals("Invalid data for `LIST` expected a bson array found: INT32", exception.message) + + exception = + assertThrows("Invalid complex types - map") { + val data = BsonDocument.parse("""{"_id": "myId", "nested": 123}""") + val codec = KotlinSerializerCodec.create() + codec?.decode(BsonDocumentReader(data), DecoderContext.builder().build()) + } + assertEquals("Invalid data for `MAP` expected a bson document found: INT32", exception.message) + + exception = + assertThrows("Missing discriminator") { + val data = BsonDocument.parse("""{"_id": {"$oid": "111111111111111111111111"}, "name": "string"}""") + val codec = KotlinSerializerCodec.create() + codec?.decode(BsonDocumentReader(data), DecoderContext.builder().build()) + } + assertEquals( + "Missing required discriminator field `_t` for polymorphic class: " + + "`org.bson.codecs.kotlinx.samples.SealedInterface`.", + exception.message) } @Test diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt index ea5e3fea3cd..0326827d4a7 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt @@ -245,6 +245,15 @@ data class DataClassOptionalBsonValues( @Serializable @SerialName("C") data class DataClassSealedC(val c: String) : DataClassSealed() +@Serializable +sealed interface SealedInterface { + val name: String +} + +@Serializable +data class DataClassSealedInterface(@Contextual @SerialName("_id") val id: ObjectId, override val name: String) : + SealedInterface + @Serializable data class DataClassListOfSealed(val items: List) interface DataClassOpen From d72a37937f6c50f851ecbd3c166d18097c46883f Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Fri, 15 Mar 2024 16:26:14 +0000 Subject: [PATCH 15/47] Fix kotlin style --- .../codecs/kotlinx/KotlinSerializerCodecProviderTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecProviderTest.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecProviderTest.kt index e05fc8f34f1..08527d36722 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecProviderTest.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecProviderTest.kt @@ -16,6 +16,10 @@ package org.bson.codecs.kotlinx import com.mongodb.MongoClientSettings +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue import org.bson.codecs.DecoderContext import org.bson.codecs.kotlinx.samples.DataClassParameterized import org.bson.codecs.kotlinx.samples.DataClassSealedInterface @@ -25,10 +29,6 @@ import org.bson.conversions.Bson import org.bson.json.JsonReader import org.bson.types.ObjectId import org.junit.jupiter.api.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull -import kotlin.test.assertNull -import kotlin.test.assertTrue class KotlinSerializerCodecProviderTest { From 5ecde1e791c1a5a0d503613fe38d928da3af6d49 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Tue, 2 Apr 2024 10:30:33 -0400 Subject: [PATCH 16/47] Force unique clusterTime values by splitting insert into two commands (#1356) JAVA-5397 --- .../operation/ChangeStreamOperationSpecification.groovy | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/driver-core/src/test/functional/com/mongodb/internal/operation/ChangeStreamOperationSpecification.groovy b/driver-core/src/test/functional/com/mongodb/internal/operation/ChangeStreamOperationSpecification.groovy index 2325061b25b..129289bfbba 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/operation/ChangeStreamOperationSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/internal/operation/ChangeStreamOperationSpecification.groovy @@ -519,7 +519,13 @@ class ChangeStreamOperationSpecification extends OperationFunctionalSpecificatio def cursor = execute(operation, async) when: - def expected = insertDocuments(helper, [1, 2]) + // split into two insert commands, because starting in MongoDB 8.0 the same clusterTime is applied to all documents in a bulk + // write operation, and the test relies on the clusterTime values being both ascending _and_ unique. + def expectedOne = insertDocuments(helper, [1]) + def expectedTwo = insertDocuments(helper, [2]) + def expected = [] + expected.addAll(expectedOne) + expected.addAll(expectedTwo) def result = next(cursor, async, 2) then: From c0b5ba4acd6b8d3e5113f3653ec78ae4ebfa3d0c Mon Sep 17 00:00:00 2001 From: Maxim Katcharov Date: Mon, 18 Mar 2024 08:05:38 -0600 Subject: [PATCH 17/47] Skip rangePreview tests on server 8.0+ (#1345) * Temporarily skip QE range tests on 8.0+ servers. JAVA-5321 * Skip ClientSideEncryptionRangeExplicitEncryptionTest on 8.0+ servers JAVA-5321 --------- Co-authored-by: Jeff Yemin --- .../legacy/fle2v2-Range-Date-Aggregate.json | 4 ++-- .../legacy/fle2v2-Range-Date-Correctness.json | 4 ++-- .../legacy/fle2v2-Range-Date-Delete.json | 4 ++-- .../legacy/fle2v2-Range-Date-FindOneAndUpdate.json | 4 ++-- .../legacy/fle2v2-Range-Date-InsertFind.json | 4 ++-- .../legacy/fle2v2-Range-Date-Update.json | 4 ++-- .../legacy/fle2v2-Range-Decimal-Aggregate.json | 4 ++-- .../legacy/fle2v2-Range-Decimal-Correctness.json | 4 ++-- .../legacy/fle2v2-Range-Decimal-Delete.json | 4 ++-- .../legacy/fle2v2-Range-Decimal-FindOneAndUpdate.json | 4 ++-- .../legacy/fle2v2-Range-Decimal-InsertFind.json | 4 ++-- .../legacy/fle2v2-Range-Decimal-Update.json | 4 ++-- .../legacy/fle2v2-Range-DecimalPrecision-Aggregate.json | 4 ++-- .../legacy/fle2v2-Range-DecimalPrecision-Correctness.json | 4 ++-- .../legacy/fle2v2-Range-DecimalPrecision-Delete.json | 4 ++-- .../fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json | 4 ++-- .../legacy/fle2v2-Range-DecimalPrecision-InsertFind.json | 4 ++-- .../legacy/fle2v2-Range-DecimalPrecision-Update.json | 4 ++-- .../legacy/fle2v2-Range-Double-Aggregate.json | 4 ++-- .../legacy/fle2v2-Range-Double-Correctness.json | 4 ++-- .../legacy/fle2v2-Range-Double-Delete.json | 4 ++-- .../legacy/fle2v2-Range-Double-FindOneAndUpdate.json | 4 ++-- .../legacy/fle2v2-Range-Double-InsertFind.json | 4 ++-- .../legacy/fle2v2-Range-Double-Update.json | 4 ++-- .../legacy/fle2v2-Range-DoublePrecision-Aggregate.json | 4 ++-- .../legacy/fle2v2-Range-DoublePrecision-Correctness.json | 4 ++-- .../legacy/fle2v2-Range-DoublePrecision-Delete.json | 4 ++-- .../legacy/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json | 4 ++-- .../legacy/fle2v2-Range-DoublePrecision-InsertFind.json | 4 ++-- .../legacy/fle2v2-Range-DoublePrecision-Update.json | 4 ++-- .../legacy/fle2v2-Range-Int-Aggregate.json | 4 ++-- .../legacy/fle2v2-Range-Int-Correctness.json | 4 ++-- .../legacy/fle2v2-Range-Int-Delete.json | 4 ++-- .../legacy/fle2v2-Range-Int-FindOneAndUpdate.json | 4 ++-- .../legacy/fle2v2-Range-Int-InsertFind.json | 4 ++-- .../legacy/fle2v2-Range-Int-Update.json | 4 ++-- .../legacy/fle2v2-Range-Long-Aggregate.json | 4 ++-- .../legacy/fle2v2-Range-Long-Correctness.json | 4 ++-- .../legacy/fle2v2-Range-Long-Delete.json | 4 ++-- .../legacy/fle2v2-Range-Long-FindOneAndUpdate.json | 4 ++-- .../legacy/fle2v2-Range-Long-InsertFind.json | 4 ++-- .../legacy/fle2v2-Range-Long-Update.json | 4 ++-- .../client-side-encryption/legacy/fle2v2-Range-WrongType.json | 4 ++-- ...stractClientSideEncryptionRangeExplicitEncryptionTest.java | 2 ++ 44 files changed, 88 insertions(+), 86 deletions(-) diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Aggregate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Aggregate.json index dea821bd1e8..9eaabe0d71a 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Aggregate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Aggregate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Correctness.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Correctness.json index 9e4f5258776..fa887e08928 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Correctness.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Correctness.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Delete.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Delete.json index 7f4094f50cc..cce4faf1887 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Delete.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Delete.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-FindOneAndUpdate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-FindOneAndUpdate.json index 5ec0601603d..4392b676860 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-FindOneAndUpdate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-FindOneAndUpdate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-InsertFind.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-InsertFind.json index efce1511c06..27ce7881df1 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-InsertFind.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-InsertFind.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Update.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Update.json index 7f9fadcda45..f7d5a6af665 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Update.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Date-Update.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Aggregate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Aggregate.json index fb129392b18..401ee34e3f2 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Aggregate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Aggregate.json @@ -2,10 +2,10 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Correctness.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Correctness.json index 5120aecb7a0..758d3e57325 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Correctness.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Correctness.json @@ -2,10 +2,10 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Delete.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Delete.json index de81159b43e..24a08f318ce 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Delete.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Delete.json @@ -2,10 +2,10 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-FindOneAndUpdate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-FindOneAndUpdate.json index 36cf91c88c2..2a8070ecf9d 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-FindOneAndUpdate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-FindOneAndUpdate.json @@ -2,10 +2,10 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-InsertFind.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-InsertFind.json index 6b5a642aa82..2ef63f42b99 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-InsertFind.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-InsertFind.json @@ -2,10 +2,10 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Update.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Update.json index 8cfb7b525b6..8064eb1b189 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Update.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Decimal-Update.json @@ -2,10 +2,10 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Aggregate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Aggregate.json index 801beefe180..8cf143c0945 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Aggregate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Aggregate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Correctness.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Correctness.json index b8a6953611d..a4b06998f7e 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Correctness.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Correctness.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Delete.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Delete.json index 1abb59bfd19..fad8234838a 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Delete.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Delete.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json index 8d763431fac..fb8f4f4140d 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-InsertFind.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-InsertFind.json index 5407fba18b6..79562802e6f 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-InsertFind.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-InsertFind.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Update.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Update.json index e5d1a4e0592..cc93b76948c 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Update.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DecimalPrecision-Update.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Aggregate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Aggregate.json index d8c9cacdccf..79f26660f24 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Aggregate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Aggregate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Correctness.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Correctness.json index 65594bcb110..117e56af620 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Correctness.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Correctness.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Delete.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Delete.json index 392e722f1f0..40d8ed5bb2e 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Delete.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Delete.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-FindOneAndUpdate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-FindOneAndUpdate.json index bbcfb321f50..f0893ce6612 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-FindOneAndUpdate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-FindOneAndUpdate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-InsertFind.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-InsertFind.json index 9f2c7c99115..d3dc2f830c0 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-InsertFind.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-InsertFind.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Update.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Update.json index ce03576f883..9d6a1fbfdd1 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Update.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Double-Update.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Aggregate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Aggregate.json index b121c72f149..4188685a2c0 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Aggregate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Aggregate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Correctness.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Correctness.json index 6b42ecfe82a..60f1ea7a333 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Correctness.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Correctness.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Delete.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Delete.json index a5c397d0be4..4ed591d3f88 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Delete.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Delete.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json index b6df9463e8e..d8fbbfae73b 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-InsertFind.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-InsertFind.json index 1cea25545ba..4213b066d1c 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-InsertFind.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-InsertFind.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Update.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Update.json index 7703c9057d2..89eb4c338d7 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Update.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-DoublePrecision-Update.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Aggregate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Aggregate.json index 9c2536264d8..686f0241bae 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Aggregate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Aggregate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Correctness.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Correctness.json index 58ccf3efc89..2964624f22b 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Correctness.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Correctness.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Delete.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Delete.json index b20b2750bbb..531b3e7590c 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Delete.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Delete.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-FindOneAndUpdate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-FindOneAndUpdate.json index f9c189ace90..402086cdb6b 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-FindOneAndUpdate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-FindOneAndUpdate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-InsertFind.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-InsertFind.json index 874d4760c86..965b8a55163 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-InsertFind.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-InsertFind.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Update.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Update.json index c2b62b4d1c5..6cf44ac782d 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Update.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Int-Update.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Aggregate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Aggregate.json index afc0f97be19..6edb38a800c 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Aggregate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Aggregate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Correctness.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Correctness.json index cda941de8a7..3d33f7381bb 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Correctness.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Correctness.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Delete.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Delete.json index ad344e21b48..1b327820108 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Delete.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Delete.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-FindOneAndUpdate.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-FindOneAndUpdate.json index d4472004681..b8e3b888a8e 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-FindOneAndUpdate.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-FindOneAndUpdate.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-InsertFind.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-InsertFind.json index 4eb837f28bc..d637fcf9e73 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-InsertFind.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-InsertFind.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Update.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Update.json index 3ba7f17c14b..1b76019a4cf 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Update.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-Long-Update.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-WrongType.json b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-WrongType.json index e5e9ddc8212..704a693b8fd 100644 --- a/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-WrongType.json +++ b/driver-core/src/test/resources/client-side-encryption/legacy/fle2v2-Range-WrongType.json @@ -2,12 +2,12 @@ "runOn": [ { "minServerVersion": "7.0.0", - "serverless": "forbid", "topology": [ "replicaset", "sharded", "load-balanced" - ] + ], + "maxServerVersion": "7.99.99" } ], "database_name": "default", diff --git a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionRangeExplicitEncryptionTest.java b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionRangeExplicitEncryptionTest.java index efd630fabbb..6bb5d1d5120 100644 --- a/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionRangeExplicitEncryptionTest.java +++ b/driver-sync/src/test/functional/com/mongodb/client/AbstractClientSideEncryptionRangeExplicitEncryptionTest.java @@ -60,6 +60,7 @@ import static com.mongodb.ClusterFixture.isServerlessTest; import static com.mongodb.ClusterFixture.isStandalone; import static com.mongodb.ClusterFixture.serverVersionAtLeast; +import static com.mongodb.ClusterFixture.serverVersionLessThan; import static com.mongodb.client.Fixture.getDefaultDatabase; import static com.mongodb.client.Fixture.getDefaultDatabaseName; import static com.mongodb.client.Fixture.getMongoClient; @@ -91,6 +92,7 @@ public abstract class AbstractClientSideEncryptionRangeExplicitEncryptionTest { @BeforeEach public void setUp(final Type type) { + assumeTrue(serverVersionLessThan(8, 0)); assumeTrue(serverVersionAtLeast(6, 2)); assumeFalse(isStandalone()); assumeFalse(isServerlessTest()); From e31340fa82c1fa8df86980f3c9e5f66d23b8c8c5 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Wed, 3 Apr 2024 11:16:41 +0100 Subject: [PATCH 18/47] Expand bounds for distinct and MongoIterable#map (#1352) Allow for nullable types in those scenarios. JAVA-5358 --- driver-kotlin-coroutine/build.gradle.kts | 1 + .../kotlin/client/coroutine/SmokeTests.kt | 101 ++++++++++++++++++ .../com/mongodb/kotlin/client/SmokeTests.kt | 89 +++++++++++++++ .../mongodb/kotlin/client/DistinctIterable.kt | 2 +- .../mongodb/kotlin/client/MongoCollection.kt | 8 +- .../com/mongodb/kotlin/client/MongoCursor.kt | 4 +- .../mongodb/kotlin/client/MongoIterable.kt | 4 +- 7 files changed, 200 insertions(+), 9 deletions(-) create mode 100644 driver-kotlin-coroutine/src/integration/kotlin/com/mongodb/kotlin/client/coroutine/SmokeTests.kt create mode 100644 driver-kotlin-sync/src/integration/kotlin/com/mongodb/kotlin/client/SmokeTests.kt diff --git a/driver-kotlin-coroutine/build.gradle.kts b/driver-kotlin-coroutine/build.gradle.kts index 1467c832abe..abd81fcd1d3 100644 --- a/driver-kotlin-coroutine/build.gradle.kts +++ b/driver-kotlin-coroutine/build.gradle.kts @@ -75,6 +75,7 @@ dependencies { testImplementation("io.github.classgraph:classgraph:4.8.154") integrationTestImplementation("org.jetbrains.kotlin:kotlin-test-junit") + integrationTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test") integrationTestImplementation(project(path = ":driver-sync")) integrationTestImplementation(project(path = ":driver-core")) integrationTestImplementation(project(path = ":bson")) diff --git a/driver-kotlin-coroutine/src/integration/kotlin/com/mongodb/kotlin/client/coroutine/SmokeTests.kt b/driver-kotlin-coroutine/src/integration/kotlin/com/mongodb/kotlin/client/coroutine/SmokeTests.kt new file mode 100644 index 00000000000..db51912d17c --- /dev/null +++ b/driver-kotlin-coroutine/src/integration/kotlin/com/mongodb/kotlin/client/coroutine/SmokeTests.kt @@ -0,0 +1,101 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mongodb.kotlin.client.coroutine + +import com.mongodb.client.Fixture.getDefaultDatabaseName +import com.mongodb.client.Fixture.getMongoClientSettings +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.flow.toSet +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest +import org.bson.Document +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +@OptIn(ExperimentalCoroutinesApi::class) +class SmokeTests { + + @AfterEach + fun afterEach() { + runBlocking { database?.drop() } + } + + @Test + @DisplayName("distinct and return nulls") + fun testDistinctNullable() = runTest { + collection!!.insertMany( + listOf( + Document.parse("{_id: 1, a: 0}"), + Document.parse("{_id: 2, a: 1}"), + Document.parse("{_id: 3, a: 0}"), + Document.parse("{_id: 4, a: null}"))) + + // nulls are auto excluded in reactive streams! + val actual = collection!!.distinct("a").toSet() + assertEquals(setOf(0, 1), actual) + } + + @Test + @DisplayName("mapping can return nulls") + fun testMongoIterableMap() = runTest { + collection!!.insertMany( + listOf( + Document.parse("{_id: 1, a: 0}"), + Document.parse("{_id: 2, a: 1}"), + Document.parse("{_id: 3, a: 0}"), + Document.parse("{_id: 4, a: null}"))) + + val actual = collection!!.find().map { it["a"] as Int? }.toList() + assertContentEquals(listOf(0, 1, 0, null), actual) + } + + companion object { + + private var mongoClient: MongoClient? = null + private var database: MongoDatabase? = null + private var collection: MongoCollection? = null + + @BeforeAll + @JvmStatic + internal fun beforeAll() { + runBlocking { + mongoClient = MongoClient.create(getMongoClientSettings()) + database = mongoClient?.getDatabase(getDefaultDatabaseName()) + database?.drop() + collection = database?.getCollection("SmokeTests") + } + } + + @AfterAll + @JvmStatic + internal fun afterAll() { + runBlocking { + collection = null + database?.drop() + database = null + mongoClient?.close() + mongoClient = null + } + } + } +} diff --git a/driver-kotlin-sync/src/integration/kotlin/com/mongodb/kotlin/client/SmokeTests.kt b/driver-kotlin-sync/src/integration/kotlin/com/mongodb/kotlin/client/SmokeTests.kt new file mode 100644 index 00000000000..3fc601d6425 --- /dev/null +++ b/driver-kotlin-sync/src/integration/kotlin/com/mongodb/kotlin/client/SmokeTests.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mongodb.kotlin.client + +import com.mongodb.client.Fixture.getDefaultDatabaseName +import com.mongodb.client.Fixture.getMongoClientSettings +import kotlin.test.assertContentEquals +import org.bson.Document +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +class SmokeTests { + + @AfterEach + fun afterEach() { + database?.drop() + } + + @Test + @DisplayName("distinct and return nulls") + fun testDistinctNullable() { + collection!!.insertMany( + listOf( + Document.parse("{_id: 1, a: 0}"), + Document.parse("{_id: 2, a: 1}"), + Document.parse("{_id: 3, a: 0}"), + Document.parse("{_id: 4, a: null}"))) + + val actual = collection!!.distinct("a").toList().toSet() + assertEquals(setOf(null, 0, 1), actual) + } + + @Test + @DisplayName("mapping can return nulls") + fun testMongoIterableMap() { + collection!!.insertMany( + listOf( + Document.parse("{_id: 1, a: 0}"), + Document.parse("{_id: 2, a: 1}"), + Document.parse("{_id: 3, a: 0}"), + Document.parse("{_id: 4, a: null}"))) + + val actual = collection!!.find().map { it["a"] }.toList() + assertContentEquals(listOf(0, 1, 0, null), actual) + } + + companion object { + + private var mongoClient: MongoClient? = null + private var database: MongoDatabase? = null + private var collection: MongoCollection? = null + + @BeforeAll + @JvmStatic + internal fun beforeAll() { + mongoClient = MongoClient.create(getMongoClientSettings()) + database = mongoClient?.getDatabase(getDefaultDatabaseName()) + database?.drop() + collection = database?.getCollection("SmokeTests") + } + + @AfterAll + @JvmStatic + internal fun afterAll() { + collection = null + database?.drop() + database = null + mongoClient?.close() + mongoClient = null + } + } +} diff --git a/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/DistinctIterable.kt b/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/DistinctIterable.kt index b630af52517..de77215d033 100644 --- a/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/DistinctIterable.kt +++ b/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/DistinctIterable.kt @@ -27,7 +27,7 @@ import org.bson.conversions.Bson * @param T The type of the result. * @see [Distinct command](https://www.mongodb.com/docs/manual/reference/command/distinct/) */ -public class DistinctIterable(private val wrapped: JDistinctIterable) : MongoIterable(wrapped) { +public class DistinctIterable(private val wrapped: JDistinctIterable) : MongoIterable(wrapped) { /** * Sets the number of documents to return per batch. * diff --git a/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoCollection.kt b/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoCollection.kt index 1529af7eaba..786140caf12 100644 --- a/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoCollection.kt +++ b/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoCollection.kt @@ -219,7 +219,7 @@ public class MongoCollection(private val wrapped: JMongoCollection) * @return an iterable of distinct values * @see [Distinct command](https://www.mongodb.com/docs/manual/reference/command/distinct/) */ - public fun distinct( + public fun distinct( fieldName: String, filter: Bson = BsonDocument(), resultClass: Class @@ -236,7 +236,7 @@ public class MongoCollection(private val wrapped: JMongoCollection) * @return an iterable of distinct values * @see [Distinct command](https://www.mongodb.com/docs/manual/reference/command/distinct/) */ - public fun distinct( + public fun distinct( clientSession: ClientSession, fieldName: String, filter: Bson = BsonDocument(), @@ -252,7 +252,7 @@ public class MongoCollection(private val wrapped: JMongoCollection) * @return an iterable of distinct values * @see [Distinct command](https://www.mongodb.com/docs/manual/reference/command/distinct/) */ - public inline fun distinct( + public inline fun distinct( fieldName: String, filter: Bson = BsonDocument() ): DistinctIterable = distinct(fieldName, filter, R::class.java) @@ -267,7 +267,7 @@ public class MongoCollection(private val wrapped: JMongoCollection) * @return an iterable of distinct values * @see [Distinct command](https://www.mongodb.com/docs/manual/reference/command/distinct/) */ - public inline fun distinct( + public inline fun distinct( clientSession: ClientSession, fieldName: String, filter: Bson = BsonDocument() diff --git a/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoCursor.kt b/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoCursor.kt index 5c757bf5e65..b407195b079 100644 --- a/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoCursor.kt +++ b/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoCursor.kt @@ -36,7 +36,7 @@ import org.bson.BsonDocument * * @param T The type of documents the cursor contains */ -public sealed interface MongoCursor : Iterator, Closeable { +public sealed interface MongoCursor : Iterator, Closeable { /** * Gets the number of results available locally without blocking, which may be 0. @@ -90,7 +90,7 @@ public sealed interface MongoChangeStreamCursor : MongoCursor { public val resumeToken: BsonDocument? } -internal class MongoCursorImpl(private val wrapped: JMongoCursor) : MongoCursor { +internal class MongoCursorImpl(private val wrapped: JMongoCursor) : MongoCursor { override fun hasNext(): Boolean = wrapped.hasNext() diff --git a/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoIterable.kt b/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoIterable.kt index fffcea2ce76..b3c37d05d43 100644 --- a/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoIterable.kt +++ b/driver-kotlin-sync/src/main/kotlin/com/mongodb/kotlin/client/MongoIterable.kt @@ -23,7 +23,7 @@ import com.mongodb.client.MongoIterable as JMongoIterable * * @param T The type that this iterable will decode documents to. */ -public open class MongoIterable(private val delegate: JMongoIterable) { +public open class MongoIterable(private val delegate: JMongoIterable) { /** * Returns a cursor used for iterating over elements of type `T. The cursor is primarily used for change streams. @@ -71,7 +71,7 @@ public open class MongoIterable(private val delegate: JMongoIterable * @param transform a function that maps from the source to the target document type * @return an iterable which maps T to U */ - public fun map(transform: (T) -> R): MongoIterable = MongoIterable(delegate.map(transform)) + public fun map(transform: (T) -> R): MongoIterable = MongoIterable(delegate.map(transform)) /** Performs the given [action] on each element and safely closes the cursor. */ public fun forEach(action: (T) -> Unit): Unit = use { it.forEach(action) } From b6df4ec7defeb5951ed112b53361408bb98ced16 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Wed, 3 Apr 2024 11:40:39 -0400 Subject: [PATCH 19/47] Version: bump 4.11.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index e53021499a1..1834d660ac2 100644 --- a/build.gradle +++ b/build.gradle @@ -74,7 +74,7 @@ configure(coreProjects) { apply plugin: 'idea' group = 'org.mongodb' - version = '4.11.2-SNAPSHOT' + version = '4.11.2' repositories { mavenLocal() From 7d80e833e1287c902d9413f18d11abd382311bcb Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Wed, 3 Apr 2024 11:40:52 -0400 Subject: [PATCH 20/47] Version: bump 4.11.3-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1834d660ac2..e40ec7359e2 100644 --- a/build.gradle +++ b/build.gradle @@ -74,7 +74,7 @@ configure(coreProjects) { apply plugin: 'idea' group = 'org.mongodb' - version = '4.11.2' + version = '4.11.3-SNAPSHOT' repositories { mavenLocal() From ca7fc160be9642b917f0e06a17e1a30d80235c26 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Wed, 3 Apr 2024 15:15:17 -0400 Subject: [PATCH 21/47] Replace sh with bash (#1358) JAVA-5359 --- .evergreen/.evg.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.evergreen/.evg.yml b/.evergreen/.evg.yml index 4aa9ec762e9..9ac7cd63352 100644 --- a/.evergreen/.evg.yml +++ b/.evergreen/.evg.yml @@ -150,7 +150,7 @@ functions: ${PREPARE_SHELL} REQUIRE_API_VERSION=${REQUIRE_API_VERSION} LOAD_BALANCER=${LOAD_BALANCER} MONGODB_VERSION=${VERSION} TOPOLOGY=${TOPOLOGY} \ AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} \ - INSTALL_LEGACY_SHELL=${INSTALL_LEGACY_SHELL} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh + INSTALL_LEGACY_SHELL=${INSTALL_LEGACY_SHELL} bash ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh # run-orchestration generates expansion file with the MONGODB_URI for the cluster - command: expansions.update params: @@ -628,7 +628,7 @@ functions: OCSP_TLS_SHOULD_SUCCEED="${OCSP_TLS_SHOULD_SUCCEED}" \ OCSP_MUST_STAPLE="${OCSP_MUST_STAPLE}" \ JAVA_VERSION="${JAVA_VERSION}" \ - sh ${PROJECT_DIRECTORY}/.evergreen/run-ocsp-test.sh + bash ${PROJECT_DIRECTORY}/.evergreen/run-ocsp-test.sh "run-valid-ocsp-server-ca-responder": - command: shell.exec From 9b7bbdb93ff5bbc7a5779c1079b46b76c75c9f44 Mon Sep 17 00:00:00 2001 From: Viacheslav Babanin Date: Fri, 28 Jun 2024 09:04:20 -0700 Subject: [PATCH 22/47] Extend the regex pattern to allow top-level domains (TLDs) up to 63 characters to comply with RFC 1034 standard. (#1427) (#1431) This is a backport of https://github.com/mongodb/mongo-java-driver/pull/1427 JAVA-5490 --- .../mongodb/internal/connection/DomainNameUtils.java | 2 +- .../internal/connection/DomainNameUtilsTest.java | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/driver-core/src/main/com/mongodb/internal/connection/DomainNameUtils.java b/driver-core/src/main/com/mongodb/internal/connection/DomainNameUtils.java index a1f0938e104..b64ea64ae24 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/DomainNameUtils.java +++ b/driver-core/src/main/com/mongodb/internal/connection/DomainNameUtils.java @@ -22,7 +22,7 @@ */ public class DomainNameUtils { private static final Pattern DOMAIN_PATTERN = - Pattern.compile("^(?=.{1,255}$)((([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}|localhost))$"); + Pattern.compile("^(?=.{1,255}$)((([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,63}|localhost))$"); static boolean isDomainName(final String domainName) { return DOMAIN_PATTERN.matcher(domainName).matches(); diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/DomainNameUtilsTest.java b/driver-core/src/test/functional/com/mongodb/internal/connection/DomainNameUtilsTest.java index cc987cacf62..43abfa5b9f7 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/DomainNameUtilsTest.java +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/DomainNameUtilsTest.java @@ -32,23 +32,25 @@ class DomainNameUtilsTest { "123numbers.com", "mixed-123domain.net", "longdomainnameabcdefghijk.com", + "i-0123456789abcdef.ec2.internal", + "ip-10-24-34-0.ec2.internal", "xn--frosch-6ya.com", "xn--emoji-grinning-3s0b.org", "xn--bcher-kva.ch", "localhost", - "abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyz.com", + "abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyz.com", //63 characters label name. + "a.abcdefghijklmnopqrstuvwxyzabcdefghjklabcdefghijklmnopqrstuvwxyz", //63 characters TLD. "xn--weihnachten-uzb.org", "sub.domain.com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain." + "com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain." + "com.domain.com.sub.domain.subb.com" //255 characters }) void shouldReturnTrueWithValidHostName(final String hostname) { - Assertions.assertTrue(isDomainName(hostname)); + Assertions.assertTrue(isDomainName(hostname), hostname + " is not a valid domain name"); } @ParameterizedTest @ValueSource(strings = { - "xn--tst-0qa.example", "xn--frosch-6ya.w23", "-special_chars_$$.net", "special_chars_$$.net", @@ -60,7 +62,8 @@ void shouldReturnTrueWithValidHostName(final String hostname) { "notlocalhost", "домен.com", //NON-ASCII "ẞẞ.com", //NON-ASCII - "abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyzl.com", + "abcdefghijklmnopqrstuvwxyz0123456789-abcdefghijklmnopqrstuvwxyzl.com", //64 characters label name. + "a.abcdefghijklmnopqrstuvwxyzabcdefghjklabcdefghijklmnopqrstuvwxyza", //64 characters TLD. "this-domain-is-really-long-because-it-just-keeps-going-and-going-and-its-still-not-done-yet-because-theres-more.net", "verylongsubdomainnamethatisreallylongandmaycausetroubleforparsing.example", "sub.domain.com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain.com.sub.domain." From 11a4f923ec42f7ff85b9686ae912cf7c349be9c9 Mon Sep 17 00:00:00 2001 From: Cliffred van Velzen Date: Mon, 1 Jul 2024 15:09:49 +0200 Subject: [PATCH 23/47] JAVA-5342 Fix encoding generics with nullable type parameters (#1317) --- .../org/bson/codecs/kotlinx/BsonEncoder.kt | 21 ++++++++++++++++- .../kotlinx/KotlinSerializerCodecTest.kt | 23 +++++++++++++++++++ .../codecs/kotlinx/samples/DataClasses.kt | 4 ++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonEncoder.kt b/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonEncoder.kt index 2e68b992700..b3ae0c8cdf4 100644 --- a/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonEncoder.kt +++ b/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonEncoder.kt @@ -139,6 +139,18 @@ internal class DefaultBsonEncoder( return true } + override fun encodeSerializableValue(serializer: SerializationStrategy, value: T) { + deferredElementName?.let { + if (value != null || configuration.explicitNulls) { + encodeName(it) + super.encodeSerializableValue(serializer, value) + } else { + deferredElementName = null + } + } + ?: super.encodeSerializableValue(serializer, value) + } + override fun encodeNullableSerializableValue(serializer: SerializationStrategy, value: T?) { deferredElementName?.let { if (value != null || configuration.explicitNulls) { @@ -158,7 +170,14 @@ internal class DefaultBsonEncoder( override fun encodeDouble(value: Double) = writer.writeDouble(value) override fun encodeInt(value: Int) = writer.writeInt32(value) override fun encodeLong(value: Long) = writer.writeInt64(value) - override fun encodeNull() = writer.writeNull() + override fun encodeNull() { + deferredElementName?.let { + if (configuration.explicitNulls) { + encodeName(it) + } + } + writer.writeNull() + } override fun encodeString(value: String) { when (state) { diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt index 14fcfa8a01c..0aed60b27ba 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt @@ -33,6 +33,7 @@ import org.bson.BsonUndefined import org.bson.codecs.DecoderContext import org.bson.codecs.EncoderContext import org.bson.codecs.configuration.CodecConfigurationException +import org.bson.codecs.kotlinx.samples.Box import org.bson.codecs.kotlinx.samples.DataClassBsonValues import org.bson.codecs.kotlinx.samples.DataClassContainsOpen import org.bson.codecs.kotlinx.samples.DataClassContainsValueClass @@ -76,6 +77,7 @@ import org.bson.codecs.kotlinx.samples.DataClassWithMutableMap import org.bson.codecs.kotlinx.samples.DataClassWithMutableSet import org.bson.codecs.kotlinx.samples.DataClassWithNestedParameterized import org.bson.codecs.kotlinx.samples.DataClassWithNestedParameterizedDataClass +import org.bson.codecs.kotlinx.samples.DataClassWithNullableGeneric import org.bson.codecs.kotlinx.samples.DataClassWithNulls import org.bson.codecs.kotlinx.samples.DataClassWithPair import org.bson.codecs.kotlinx.samples.DataClassWithParameterizedDataClass @@ -202,6 +204,27 @@ class KotlinSerializerCodecTest { assertRoundTrips(expectedNulls, dataClass, altConfiguration) } + @Test + fun testDataClassWithNullableGenericsNotNull() { + val expected = + """{ + | "box": {"boxed": "String"} + |}""" + .trimMargin() + + val dataClass = DataClassWithNullableGeneric(Box("String")) + assertRoundTrips(expected, dataClass) + } + + @Test + fun testDataClassWithNullableGenericsNull() { + val expectedDefault = """{"box": {}}""" + val dataClass = DataClassWithNullableGeneric(Box(null)) + assertRoundTrips(expectedDefault, dataClass) + val expectedNull = """{"box": {"boxed": null}}""" + assertRoundTrips(expectedNull, dataClass, altConfiguration) + } + @Test fun testDataClassSelfReferential() { val expected = diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt index 0326827d4a7..a58ae541d03 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt @@ -294,3 +294,7 @@ data class DataClassWithFailingInit(val id: String) { } @Serializable data class DataClassWithSequence(val value: Sequence) + +@Serializable data class Box(val boxed: T) + +@Serializable data class DataClassWithNullableGeneric(val box: Box) From 9c73aeeafa84086e30fafcf2d1a16cbc0a569c1d Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Mon, 1 Jul 2024 14:14:23 +0100 Subject: [PATCH 24/47] Ported tests from bson-kotlinx to bson-kotlin (#1434) JAVA-5342 Co-authored-by: Cliffred van Velzen --- .../bson/codecs/kotlin/DataClassCodecTest.kt | 21 +++++++++++++++++++ .../bson/codecs/kotlin/samples/DataClasses.kt | 7 +++++++ 2 files changed, 28 insertions(+) diff --git a/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecTest.kt b/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecTest.kt index c115b051529..d2dbfc580cc 100644 --- a/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecTest.kt +++ b/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecTest.kt @@ -23,6 +23,7 @@ import org.bson.codecs.DecoderContext import org.bson.codecs.EncoderContext import org.bson.codecs.configuration.CodecConfigurationException import org.bson.codecs.configuration.CodecRegistries.fromProviders +import org.bson.codecs.kotlin.samples.Box import org.bson.codecs.kotlin.samples.DataClassEmbedded import org.bson.codecs.kotlin.samples.DataClassListOfDataClasses import org.bson.codecs.kotlin.samples.DataClassListOfListOfDataClasses @@ -55,6 +56,7 @@ import org.bson.codecs.kotlin.samples.DataClassWithMutableMap import org.bson.codecs.kotlin.samples.DataClassWithMutableSet import org.bson.codecs.kotlin.samples.DataClassWithNestedParameterized import org.bson.codecs.kotlin.samples.DataClassWithNestedParameterizedDataClass +import org.bson.codecs.kotlin.samples.DataClassWithNullableGeneric import org.bson.codecs.kotlin.samples.DataClassWithNulls import org.bson.codecs.kotlin.samples.DataClassWithObjectIdAndBsonDocument import org.bson.codecs.kotlin.samples.DataClassWithPair @@ -131,6 +133,25 @@ class DataClassCodecTest { assertDecodesTo(withStoredNulls, dataClass) } + @Test + fun testDataClassWithNullableGenericsNotNull() { + val expected = + """{ + | "box": {"boxed": "String"} + |}""" + .trimMargin() + + val dataClass = DataClassWithNullableGeneric(Box("String")) + assertRoundTrips(expected, dataClass) + } + + @Test + fun testDataClassWithNullableGenericsNull() { + val expected = """{"box": {}}""" + val dataClass = DataClassWithNullableGeneric(Box(null)) + assertRoundTrips(expected, dataClass) + } + @Test fun testDataClassSelfReferential() { val expected = diff --git a/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/samples/DataClasses.kt b/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/samples/DataClasses.kt index eaa87ca603b..a320470cf23 100644 --- a/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/samples/DataClasses.kt +++ b/bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/samples/DataClasses.kt @@ -15,6 +15,7 @@ */ package org.bson.codecs.kotlin.samples +import kotlin.time.Duration import org.bson.BsonDocument import org.bson.BsonMaxKey import org.bson.BsonType @@ -159,3 +160,9 @@ data class DataClassWithFailingInit(val id: String) { } data class DataClassWithSequence(val value: Sequence) + +data class DataClassWithJVMErasure(val duration: Duration, val ints: List) + +data class Box(val boxed: T) + +data class DataClassWithNullableGeneric(val box: Box) From 1aafa7ada7464cc46f7385f2b9fe1a5a924360e8 Mon Sep 17 00:00:00 2001 From: Viacheslav Babanin Date: Tue, 16 Jul 2024 08:04:23 -0700 Subject: [PATCH 25/47] Enhance KotlinSerializer with value codecs for widening primitive conversion. (#1301) JAVA-5303 --- .../org/bson/codecs/kotlinx/BsonDecoder.kt | 21 +++--- .../kotlinx/KotlinSerializerCodecTest.kt | 69 ++++++++++++++++--- .../org/bson/codecs/AtomicIntegerCodec.java | 2 +- .../main/org/bson/codecs/AtomicLongCodec.java | 2 +- bson/src/main/org/bson/codecs/ByteCodec.java | 10 +-- .../main/org/bson/codecs/CharacterCodec.java | 11 +-- .../src/main/org/bson/codecs/DoubleCodec.java | 2 +- bson/src/main/org/bson/codecs/FloatCodec.java | 10 +-- .../main/org/bson/codecs/IntegerCodec.java | 2 +- bson/src/main/org/bson/codecs/LongCodec.java | 2 +- bson/src/main/org/bson/codecs/ShortCodec.java | 10 +-- .../NumberCodecHelper.java | 37 ++++++++-- .../org/bson/internal/StringCodecHelper.java | 46 +++++++++++++ config/spotbugs/exclude.xml | 6 ++ 14 files changed, 170 insertions(+), 60 deletions(-) rename bson/src/main/org/bson/{codecs => internal}/NumberCodecHelper.java (78%) create mode 100644 bson/src/main/org/bson/internal/StringCodecHelper.java diff --git a/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonDecoder.kt b/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonDecoder.kt index 435964d4ac0..38d9c23309f 100644 --- a/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonDecoder.kt +++ b/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonDecoder.kt @@ -36,6 +36,8 @@ import org.bson.BsonType import org.bson.BsonValue import org.bson.codecs.BsonValueCodec import org.bson.codecs.DecoderContext +import org.bson.internal.NumberCodecHelper +import org.bson.internal.StringCodecHelper import org.bson.types.ObjectId /** @@ -154,14 +156,17 @@ internal open class DefaultBsonDecoder( } } - override fun decodeByte(): Byte = decodeInt().toByte() - override fun decodeChar(): Char = decodeString().single() - override fun decodeFloat(): Float = decodeDouble().toFloat() - override fun decodeShort(): Short = decodeInt().toShort() - override fun decodeBoolean(): Boolean = readOrThrow({ reader.readBoolean() }, BsonType.BOOLEAN) - override fun decodeDouble(): Double = readOrThrow({ reader.readDouble() }, BsonType.DOUBLE) - override fun decodeInt(): Int = readOrThrow({ reader.readInt32() }, BsonType.INT32) - override fun decodeLong(): Long = readOrThrow({ reader.readInt64() }, BsonType.INT64) + override fun decodeByte(): Byte = NumberCodecHelper.decodeByte(reader) + + override fun decodeChar(): Char = StringCodecHelper.decodeChar(reader) + override fun decodeFloat(): Float = NumberCodecHelper.decodeFloat(reader) + + override fun decodeShort(): Short = NumberCodecHelper.decodeShort(reader) + override fun decodeBoolean(): Boolean = reader.readBoolean() + + override fun decodeDouble(): Double = NumberCodecHelper.decodeDouble(reader) + override fun decodeInt(): Int = NumberCodecHelper.decodeInt(reader) + override fun decodeLong(): Long = NumberCodecHelper.decodeLong(reader) override fun decodeString(): String = readOrThrow({ reader.readString() }, BsonType.STRING) override fun decodeNull(): Nothing? { diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt index 0aed60b27ba..30fc6f7fbb4 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt @@ -15,6 +15,7 @@ */ package org.bson.codecs.kotlinx +import java.util.stream.Stream import kotlin.test.assertEquals import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.MissingFieldException @@ -23,12 +24,17 @@ import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.plus import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.modules.subclass +import org.bson.BsonBoolean import org.bson.BsonDocument import org.bson.BsonDocumentReader import org.bson.BsonDocumentWriter +import org.bson.BsonDouble +import org.bson.BsonInt32 +import org.bson.BsonInt64 import org.bson.BsonInvalidOperationException import org.bson.BsonMaxKey import org.bson.BsonMinKey +import org.bson.BsonString import org.bson.BsonUndefined import org.bson.codecs.DecoderContext import org.bson.codecs.EncoderContext @@ -90,11 +96,12 @@ import org.bson.codecs.kotlinx.samples.SealedInterface import org.bson.codecs.kotlinx.samples.ValueClass import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource @OptIn(ExperimentalSerializationApi::class) @Suppress("LargeClass") class KotlinSerializerCodecTest { - private val numberLong = "\$numberLong" private val oid = "\$oid" private val emptyDocument = "{}" private val altConfiguration = @@ -134,15 +141,59 @@ class KotlinSerializerCodecTest { private val allBsonTypesDocument = BsonDocument.parse(allBsonTypesJson) - @Test - fun testDataClassWithSimpleValues() { - val expected = - """{"char": "c", "byte": 0, "short": 1, "int": 22, "long": {"$numberLong": "42"}, "float": 4.0, - | "double": 4.2, "boolean": true, "string": "String"}""" - .trimMargin() - val dataClass = DataClassWithSimpleValues('c', 0, 1, 22, 42L, 4.0f, 4.2, true, "String") + companion object { + @JvmStatic + fun testTypesCastingDataClassWithSimpleValues(): Stream { + return Stream.of( + BsonDocument() + .append("char", BsonString("c")) + .append("byte", BsonInt32(1)) + .append("short", BsonInt32(2)) + .append("int", BsonInt32(10)) + .append("long", BsonInt32(10)) + .append("float", BsonInt32(2)) + .append("double", BsonInt32(3)) + .append("boolean", BsonBoolean.TRUE) + .append("string", BsonString("String")), + BsonDocument() + .append("char", BsonString("c")) + .append("byte", BsonDouble(1.0)) + .append("short", BsonDouble(2.0)) + .append("int", BsonDouble(9.9999999999999992)) + .append("long", BsonDouble(9.9999999999999992)) + .append("float", BsonDouble(2.0)) + .append("double", BsonDouble(3.0)) + .append("boolean", BsonBoolean.TRUE) + .append("string", BsonString("String")), + BsonDocument() + .append("char", BsonString("c")) + .append("byte", BsonDouble(1.0)) + .append("short", BsonDouble(2.0)) + .append("int", BsonDouble(10.0)) + .append("long", BsonDouble(10.0)) + .append("float", BsonDouble(2.0)) + .append("double", BsonDouble(3.0)) + .append("boolean", BsonBoolean.TRUE) + .append("string", BsonString("String")), + BsonDocument() + .append("char", BsonString("c")) + .append("byte", BsonInt64(1)) + .append("short", BsonInt64(2)) + .append("int", BsonInt64(10)) + .append("long", BsonInt64(10)) + .append("float", BsonInt64(2)) + .append("double", BsonInt64(3)) + .append("boolean", BsonBoolean.TRUE) + .append("string", BsonString("String"))) + } + } - assertRoundTrips(expected, dataClass) + @ParameterizedTest + @MethodSource("testTypesCastingDataClassWithSimpleValues") + fun testTypesCastingDataClassWithSimpleValues(data: BsonDocument) { + val expectedDataClass = DataClassWithSimpleValues('c', 1, 2, 10, 10L, 2.0f, 3.0, true, "String") + + assertDecodesTo(data, expectedDataClass) } @Test diff --git a/bson/src/main/org/bson/codecs/AtomicIntegerCodec.java b/bson/src/main/org/bson/codecs/AtomicIntegerCodec.java index 8fd3e55876b..d8963ed40d7 100644 --- a/bson/src/main/org/bson/codecs/AtomicIntegerCodec.java +++ b/bson/src/main/org/bson/codecs/AtomicIntegerCodec.java @@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicInteger; -import static org.bson.codecs.NumberCodecHelper.decodeInt; +import static org.bson.internal.NumberCodecHelper.decodeInt; /** * Encodes and decodes {@code AtomicInteger} objects. diff --git a/bson/src/main/org/bson/codecs/AtomicLongCodec.java b/bson/src/main/org/bson/codecs/AtomicLongCodec.java index c6e053c6d9f..7f08af77961 100644 --- a/bson/src/main/org/bson/codecs/AtomicLongCodec.java +++ b/bson/src/main/org/bson/codecs/AtomicLongCodec.java @@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicLong; -import static org.bson.codecs.NumberCodecHelper.decodeLong; +import static org.bson.internal.NumberCodecHelper.decodeLong; /** * Encodes and decodes {@code AtomicLong} objects. diff --git a/bson/src/main/org/bson/codecs/ByteCodec.java b/bson/src/main/org/bson/codecs/ByteCodec.java index 26b5005ea66..e7011f8b58d 100644 --- a/bson/src/main/org/bson/codecs/ByteCodec.java +++ b/bson/src/main/org/bson/codecs/ByteCodec.java @@ -16,12 +16,10 @@ package org.bson.codecs; -import org.bson.BsonInvalidOperationException; import org.bson.BsonReader; import org.bson.BsonWriter; -import static java.lang.String.format; -import static org.bson.codecs.NumberCodecHelper.decodeInt; +import static org.bson.internal.NumberCodecHelper.decodeByte; /** * Encodes and decodes {@code Byte} objects. @@ -37,11 +35,7 @@ public void encode(final BsonWriter writer, final Byte value, final EncoderConte @Override public Byte decode(final BsonReader reader, final DecoderContext decoderContext) { - int value = decodeInt(reader); - if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { - throw new BsonInvalidOperationException(format("%s can not be converted into a Byte.", value)); - } - return (byte) value; + return decodeByte(reader); } @Override diff --git a/bson/src/main/org/bson/codecs/CharacterCodec.java b/bson/src/main/org/bson/codecs/CharacterCodec.java index 0a9e6252056..4ad6efa2663 100644 --- a/bson/src/main/org/bson/codecs/CharacterCodec.java +++ b/bson/src/main/org/bson/codecs/CharacterCodec.java @@ -16,11 +16,10 @@ package org.bson.codecs; -import org.bson.BsonInvalidOperationException; import org.bson.BsonReader; import org.bson.BsonWriter; +import org.bson.internal.StringCodecHelper; -import static java.lang.String.format; import static org.bson.assertions.Assertions.notNull; /** @@ -38,13 +37,7 @@ public void encode(final BsonWriter writer, final Character value, final Encoder @Override public Character decode(final BsonReader reader, final DecoderContext decoderContext) { - String string = reader.readString(); - if (string.length() != 1) { - throw new BsonInvalidOperationException(format("Attempting to decode the string '%s' to a character, but its length is not " - + "equal to one", string)); - } - - return string.charAt(0); + return StringCodecHelper.decodeChar(reader); } @Override diff --git a/bson/src/main/org/bson/codecs/DoubleCodec.java b/bson/src/main/org/bson/codecs/DoubleCodec.java index 523042bb163..33e3f6782bd 100644 --- a/bson/src/main/org/bson/codecs/DoubleCodec.java +++ b/bson/src/main/org/bson/codecs/DoubleCodec.java @@ -19,7 +19,7 @@ import org.bson.BsonReader; import org.bson.BsonWriter; -import static org.bson.codecs.NumberCodecHelper.decodeDouble; +import static org.bson.internal.NumberCodecHelper.decodeDouble; /** * Encodes and decodes {@code Double} objects. diff --git a/bson/src/main/org/bson/codecs/FloatCodec.java b/bson/src/main/org/bson/codecs/FloatCodec.java index 84b85c5aa1b..49dc7e22aff 100644 --- a/bson/src/main/org/bson/codecs/FloatCodec.java +++ b/bson/src/main/org/bson/codecs/FloatCodec.java @@ -16,12 +16,10 @@ package org.bson.codecs; -import org.bson.BsonInvalidOperationException; import org.bson.BsonReader; import org.bson.BsonWriter; -import static java.lang.String.format; -import static org.bson.codecs.NumberCodecHelper.decodeDouble; +import static org.bson.internal.NumberCodecHelper.decodeFloat; /** * Encodes and decodes {@code Float} objects. @@ -37,11 +35,7 @@ public void encode(final BsonWriter writer, final Float value, final EncoderCont @Override public Float decode(final BsonReader reader, final DecoderContext decoderContext) { - double value = decodeDouble(reader); - if (value < -Float.MAX_VALUE || value > Float.MAX_VALUE) { - throw new BsonInvalidOperationException(format("%s can not be converted into a Float.", value)); - } - return (float) value; + return decodeFloat(reader); } @Override diff --git a/bson/src/main/org/bson/codecs/IntegerCodec.java b/bson/src/main/org/bson/codecs/IntegerCodec.java index dee6e2512fb..bb0c5c082d5 100644 --- a/bson/src/main/org/bson/codecs/IntegerCodec.java +++ b/bson/src/main/org/bson/codecs/IntegerCodec.java @@ -19,7 +19,7 @@ import org.bson.BsonReader; import org.bson.BsonWriter; -import static org.bson.codecs.NumberCodecHelper.decodeInt; +import static org.bson.internal.NumberCodecHelper.decodeInt; /** * Encodes and decodes {@code Integer} objects. diff --git a/bson/src/main/org/bson/codecs/LongCodec.java b/bson/src/main/org/bson/codecs/LongCodec.java index 29adc373488..0e16e4430bc 100644 --- a/bson/src/main/org/bson/codecs/LongCodec.java +++ b/bson/src/main/org/bson/codecs/LongCodec.java @@ -19,7 +19,7 @@ import org.bson.BsonReader; import org.bson.BsonWriter; -import static org.bson.codecs.NumberCodecHelper.decodeLong; +import static org.bson.internal.NumberCodecHelper.decodeLong; /** * Encodes and decodes {@code Long} objects. diff --git a/bson/src/main/org/bson/codecs/ShortCodec.java b/bson/src/main/org/bson/codecs/ShortCodec.java index e5aaf8f9acb..8c439e36b8d 100644 --- a/bson/src/main/org/bson/codecs/ShortCodec.java +++ b/bson/src/main/org/bson/codecs/ShortCodec.java @@ -16,12 +16,10 @@ package org.bson.codecs; -import org.bson.BsonInvalidOperationException; import org.bson.BsonReader; import org.bson.BsonWriter; -import static java.lang.String.format; -import static org.bson.codecs.NumberCodecHelper.decodeInt; +import static org.bson.internal.NumberCodecHelper.decodeShort; /** * Encodes and decodes {@code Short} objects. @@ -37,11 +35,7 @@ public void encode(final BsonWriter writer, final Short value, final EncoderCont @Override public Short decode(final BsonReader reader, final DecoderContext decoderContext) { - int value = decodeInt(reader); - if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { - throw new BsonInvalidOperationException(format("%s can not be converted into a Short.", value)); - } - return (short) value; + return decodeShort(reader); } @Override diff --git a/bson/src/main/org/bson/codecs/NumberCodecHelper.java b/bson/src/main/org/bson/internal/NumberCodecHelper.java similarity index 78% rename from bson/src/main/org/bson/codecs/NumberCodecHelper.java rename to bson/src/main/org/bson/internal/NumberCodecHelper.java index 69dfe29ac7e..faf63e56eb5 100644 --- a/bson/src/main/org/bson/codecs/NumberCodecHelper.java +++ b/bson/src/main/org/bson/internal/NumberCodecHelper.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.bson.codecs; +package org.bson.internal; import org.bson.BsonInvalidOperationException; import org.bson.BsonReader; @@ -25,9 +25,28 @@ import static java.lang.String.format; -final class NumberCodecHelper { +/** + * This class is not part of the public API. It may be removed or changed at any time. + */ +public final class NumberCodecHelper { + + public static byte decodeByte(final BsonReader reader) { + int value = decodeInt(reader); + if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) { + throw new BsonInvalidOperationException(format("%s can not be converted into a Byte.", value)); + } + return (byte) value; + } + + public static short decodeShort(final BsonReader reader) { + int value = decodeInt(reader); + if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) { + throw new BsonInvalidOperationException(format("%s can not be converted into a Short.", value)); + } + return (short) value; + } - static int decodeInt(final BsonReader reader) { + public static int decodeInt(final BsonReader reader) { int intValue; BsonType bsonType = reader.getCurrentBsonType(); switch (bsonType) { @@ -61,7 +80,7 @@ static int decodeInt(final BsonReader reader) { return intValue; } - static long decodeLong(final BsonReader reader) { + public static long decodeLong(final BsonReader reader) { long longValue; BsonType bsonType = reader.getCurrentBsonType(); switch (bsonType) { @@ -91,7 +110,15 @@ static long decodeLong(final BsonReader reader) { return longValue; } - static double decodeDouble(final BsonReader reader) { + public static float decodeFloat(final BsonReader reader) { + double value = decodeDouble(reader); + if (value < -Float.MAX_VALUE || value > Float.MAX_VALUE) { + throw new BsonInvalidOperationException(format("%s can not be converted into a Float.", value)); + } + return (float) value; + } + + public static double decodeDouble(final BsonReader reader) { double doubleValue; BsonType bsonType = reader.getCurrentBsonType(); switch (bsonType) { diff --git a/bson/src/main/org/bson/internal/StringCodecHelper.java b/bson/src/main/org/bson/internal/StringCodecHelper.java new file mode 100644 index 00000000000..04225aad939 --- /dev/null +++ b/bson/src/main/org/bson/internal/StringCodecHelper.java @@ -0,0 +1,46 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bson.internal; + +import org.bson.BsonInvalidOperationException; +import org.bson.BsonReader; +import org.bson.BsonType; + +import static java.lang.String.format; + +/** + * This class is not part of the public API. It may be removed or changed at any time. + */ +public final class StringCodecHelper { + + private StringCodecHelper(){ + //NOP + } + + public static char decodeChar(final BsonReader reader) { + BsonType currentBsonType = reader.getCurrentBsonType(); + if (currentBsonType != BsonType.STRING) { + throw new BsonInvalidOperationException(format("Invalid string type, found: %s", currentBsonType)); + } + String string = reader.readString(); + if (string.length() != 1) { + throw new BsonInvalidOperationException(format("Attempting to decode the string '%s' to a character, but its length is not " + + "equal to one", string)); + } + return string.charAt(0); + } +} diff --git a/config/spotbugs/exclude.xml b/config/spotbugs/exclude.xml index d35f0a81c8a..4320270826a 100644 --- a/config/spotbugs/exclude.xml +++ b/config/spotbugs/exclude.xml @@ -263,6 +263,12 @@ + + + + + +